mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-06 13:49:51 +02:00
Merge remote-tracking branch 'origin/master' into character_entity_fixes
Updating the branch to the latest code
This commit is contained in:
commit
ded81fcab0
92 changed files with 2006 additions and 302 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -66,6 +66,9 @@ TAGS
|
|||
*.sw[po]
|
||||
*.qmlc
|
||||
|
||||
# ignore QML compilation output
|
||||
*.qmlc
|
||||
|
||||
# ignore node files for the console
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||
const int WAIT_FOR_CHILD_MSECS = 1000;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
HANDLE PROCESS_GROUP = createProcessGroup();
|
||||
#endif
|
||||
|
||||
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||
const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks,
|
||||
|
@ -202,6 +206,10 @@ void AssignmentClientMonitor::spawnChildClient() {
|
|||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
addProcessToGroup(PROCESS_GROUP, assignmentClient->processId());
|
||||
#endif
|
||||
|
||||
QString stdoutPath, stderrPath;
|
||||
|
||||
if (_wantsChildFileLogging) {
|
||||
|
|
|
@ -82,8 +82,12 @@ bool OctreeSendThread::process() {
|
|||
if (auto node = _node.lock()) {
|
||||
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
|
||||
|
||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||
if (nodeData && !nodeData->isShuttingDown()) {
|
||||
// If we don't have the OctreeQueryNode at all
|
||||
// or it's uninitialized because we haven't received a query yet from the client
|
||||
// or we don't know where we should send packets for this node
|
||||
// or we're shutting down
|
||||
// then we can't send an entity data packet
|
||||
if (nodeData && nodeData->hasReceivedFirstQuery() && node->getActiveSocket() && !nodeData->isShuttingDown()) {
|
||||
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
||||
packetDistributor(node, nodeData, viewFrustumChanged);
|
||||
}
|
||||
|
|
|
@ -476,7 +476,9 @@ Rectangle {
|
|||
commerce.buy(itemId, itemPrice, true);
|
||||
}
|
||||
} else {
|
||||
sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
|
||||
if (urlHandler.canHandleUrl(itemHref)) {
|
||||
urlHandler.handleUrl(itemHref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -594,9 +596,7 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
text: root.isWearable ? "Wear It" : "Rez It"
|
||||
onClicked: {
|
||||
if (urlHandler.canHandleUrl(root.itemHref)) {
|
||||
urlHandler.handleUrl(root.itemHref);
|
||||
}
|
||||
sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
|
||||
rezzedNotifContainer.visible = true;
|
||||
rezzedNotifContainerTimer.start();
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ import "../audio" as HifiAudio
|
|||
Item {
|
||||
id: tablet
|
||||
objectName: "tablet"
|
||||
property int rowIndex: 0
|
||||
property int columnIndex: 0
|
||||
property int rowIndex: 6 // by default
|
||||
property int columnIndex: 1 // point to 'go to location'
|
||||
property int count: (flowMain.children.length - 1)
|
||||
|
||||
// used to look up a button by its uuid
|
||||
|
|
|
@ -1700,8 +1700,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
lastLeftHandPose = leftHandPose;
|
||||
lastRightHandPose = rightHandPose;
|
||||
|
||||
properties["local_socket_changes"] = DependencyManager::get<StatTracker>()->getStat(LOCAL_SOCKET_CHANGE_STAT).toInt();
|
||||
|
||||
UserActivityLogger::getInstance().logAction("stats", properties);
|
||||
});
|
||||
sendStatsTimer->start();
|
||||
|
@ -1825,6 +1823,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// Preload Tablet sounds
|
||||
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
|
||||
|
||||
_pendingIdleEvent = false;
|
||||
_pendingRenderEvent = false;
|
||||
|
||||
qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID());
|
||||
}
|
||||
|
||||
|
|
|
@ -708,7 +708,7 @@ private:
|
|||
|
||||
friend class RenderEventHandler;
|
||||
|
||||
std::atomic<bool> _pendingIdleEvent { false };
|
||||
std::atomic<bool> _pendingRenderEvent { false };
|
||||
std::atomic<bool> _pendingIdleEvent { true };
|
||||
std::atomic<bool> _pendingRenderEvent { true };
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "RayPickScriptingInterface.h"
|
||||
|
||||
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) :
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) :
|
||||
_renderingEnabled(enabled),
|
||||
_renderStates(renderStates),
|
||||
_defaultRenderStates(defaultRenderStates),
|
||||
|
@ -23,6 +23,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
|
|||
_centerEndY(centerEndY),
|
||||
_lockEnd(lockEnd),
|
||||
_distanceScaleEnd(distanceScaleEnd),
|
||||
_scaleWithAvatar(scaleWithAvatar),
|
||||
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps))
|
||||
{
|
||||
|
||||
|
@ -94,6 +95,10 @@ void LaserPointer::editRenderState(const std::string& state, const QVariant& sta
|
|||
if (endDim.isValid()) {
|
||||
_renderStates[state].setEndDim(vec3FromVariant(endDim));
|
||||
}
|
||||
QVariant lineWidth = pathProps.toMap()["lineWidth"];
|
||||
if (lineWidth.isValid()) {
|
||||
_renderStates[state].setLineWidth(lineWidth.toFloat());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -152,6 +157,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariant end = vec3toVariant(endVec);
|
||||
if (!renderState.getPathID().isNull()) {
|
||||
QVariantMap pathProps;
|
||||
|
@ -159,6 +165,9 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
|
|||
pathProps.insert("end", end);
|
||||
pathProps.insert("visible", true);
|
||||
pathProps.insert("ignoreRayIntersection", renderState.doesPathIgnoreRays());
|
||||
if (_scaleWithAvatar) {
|
||||
pathProps.insert("lineWidth", renderState.getLineWidth() * DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale());
|
||||
}
|
||||
qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps);
|
||||
}
|
||||
if (!renderState.getEndID().isNull()) {
|
||||
|
@ -166,7 +175,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
|
|||
glm::quat faceAvatarRotation = DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)));
|
||||
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value);
|
||||
if (_distanceScaleEnd) {
|
||||
dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec) * DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
|
||||
dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec);
|
||||
endProps.insert("dimensions", vec3toVariant(dim));
|
||||
}
|
||||
if (_centerEndY) {
|
||||
|
@ -258,6 +267,7 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons
|
|||
}
|
||||
if (!_pathID.isNull()) {
|
||||
_pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool();
|
||||
_lineWidth = qApp->getOverlays().getProperty(_pathID, "lineWidth").value.toFloat();
|
||||
}
|
||||
if (!_endID.isNull()) {
|
||||
_endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value);
|
||||
|
|
|
@ -43,6 +43,9 @@ public:
|
|||
void setEndDim(const glm::vec3& endDim) { _endDim = endDim; }
|
||||
const glm::vec3& getEndDim() const { return _endDim; }
|
||||
|
||||
void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; }
|
||||
const float& getLineWidth() const { return _lineWidth; }
|
||||
|
||||
void deleteOverlays();
|
||||
|
||||
private:
|
||||
|
@ -54,6 +57,7 @@ private:
|
|||
bool _endIgnoreRays;
|
||||
|
||||
glm::vec3 _endDim;
|
||||
float _lineWidth;
|
||||
};
|
||||
|
||||
|
||||
|
@ -66,7 +70,7 @@ public:
|
|||
typedef std::unordered_map<std::string, std::pair<float, RenderState>> DefaultRenderStateMap;
|
||||
|
||||
LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled);
|
||||
~LaserPointer();
|
||||
|
||||
QUuid getRayUID() { return _rayPickUID; }
|
||||
|
@ -97,6 +101,7 @@ private:
|
|||
bool _centerEndY;
|
||||
bool _lockEnd;
|
||||
bool _distanceScaleEnd;
|
||||
bool _scaleWithAvatar;
|
||||
LockEndObject _lockEndObject;
|
||||
|
||||
const QUuid _rayPickUID;
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
#include "LaserPointerManager.h"
|
||||
|
||||
QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) {
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) {
|
||||
QUuid result;
|
||||
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
|
||||
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, scaleWithAvatar, enabled);
|
||||
if (!laserPointer->getRayUID().isNull()) {
|
||||
result = QUuid::createUuid();
|
||||
withWriteLock([&] { _laserPointers[result] = laserPointer; });
|
||||
|
|
|
@ -25,7 +25,7 @@ class LaserPointerManager : protected ReadWriteLockable {
|
|||
|
||||
public:
|
||||
QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
|
||||
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled);
|
||||
|
||||
void removeLaserPointer(const QUuid& uid);
|
||||
void enableLaserPointer(const QUuid& uid) const;
|
||||
|
|
|
@ -51,6 +51,11 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
|
|||
enabled = propertyMap["enabled"].toBool();
|
||||
}
|
||||
|
||||
bool scaleWithAvatar = false;
|
||||
if (propertyMap["scaleWithAvatar"].isValid()) {
|
||||
scaleWithAvatar = propertyMap["scaleWithAvatar"].toBool();
|
||||
}
|
||||
|
||||
LaserPointer::RenderStateMap renderStates;
|
||||
if (propertyMap["renderStates"].isValid()) {
|
||||
QList<QVariant> renderStateVariants = propertyMap["renderStates"].toList();
|
||||
|
@ -80,7 +85,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
|
|||
}
|
||||
}
|
||||
|
||||
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
|
||||
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, scaleWithAvatar, enabled);
|
||||
}
|
||||
|
||||
void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const {
|
||||
|
|
|
@ -16,13 +16,11 @@
|
|||
#include "Application.h"
|
||||
|
||||
|
||||
const float DEFAULT_LINE_WIDTH = 1.0f;
|
||||
const bool DEFAULT_IS_SOLID = false;
|
||||
const bool DEFAULT_IS_DASHED_LINE = false;
|
||||
|
||||
Base3DOverlay::Base3DOverlay() :
|
||||
SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()),
|
||||
_lineWidth(DEFAULT_LINE_WIDTH),
|
||||
_isSolid(DEFAULT_IS_SOLID),
|
||||
_isDashedLine(DEFAULT_IS_DASHED_LINE),
|
||||
_ignoreRayIntersection(false),
|
||||
|
@ -34,7 +32,6 @@ Base3DOverlay::Base3DOverlay() :
|
|||
Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
|
||||
Overlay(base3DOverlay),
|
||||
SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()),
|
||||
_lineWidth(base3DOverlay->_lineWidth),
|
||||
_isSolid(base3DOverlay->_isSolid),
|
||||
_isDashedLine(base3DOverlay->_isDashedLine),
|
||||
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection),
|
||||
|
@ -153,12 +150,6 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
|||
setLocalOrientation(quatFromVariant(properties["orientation"]));
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
if (properties["lineWidth"].isValid()) {
|
||||
setLineWidth(properties["lineWidth"].toFloat());
|
||||
needRenderItemUpdate = true;
|
||||
}
|
||||
|
||||
if (properties["isSolid"].isValid()) {
|
||||
setIsSolid(properties["isSolid"].toBool());
|
||||
}
|
||||
|
@ -225,9 +216,6 @@ QVariant Base3DOverlay::getProperty(const QString& property) {
|
|||
if (property == "localRotation" || property == "localOrientation") {
|
||||
return quatToVariant(getLocalOrientation());
|
||||
}
|
||||
if (property == "lineWidth") {
|
||||
return _lineWidth;
|
||||
}
|
||||
if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") {
|
||||
return _isSolid;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ public:
|
|||
// TODO: consider implementing registration points in this class
|
||||
glm::vec3 getCenter() const { return getPosition(); }
|
||||
|
||||
float getLineWidth() const { return _lineWidth; }
|
||||
bool getIsSolid() const { return _isSolid; }
|
||||
bool getIsDashedLine() const { return _isDashedLine; }
|
||||
bool getIsSolidLine() const { return !_isDashedLine; }
|
||||
|
@ -47,7 +46,6 @@ public:
|
|||
bool getDrawHUDLayer() const { return _drawHUDLayer; }
|
||||
bool getIsGrabbable() const { return _isGrabbable; }
|
||||
|
||||
void setLineWidth(float lineWidth) { _lineWidth = lineWidth; }
|
||||
void setIsSolid(bool isSolid) { _isSolid = isSolid; }
|
||||
void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; }
|
||||
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
|
||||
|
@ -85,7 +83,6 @@ protected:
|
|||
void setRenderVisible(bool visible);
|
||||
const Transform& getRenderTransform() const { return _renderTransform; }
|
||||
|
||||
float _lineWidth;
|
||||
bool _isSolid;
|
||||
bool _isDashedLine;
|
||||
bool _ignoreRayIntersection;
|
||||
|
|
|
@ -33,8 +33,8 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
|
|||
_length = line3DOverlay->getLength();
|
||||
_endParentID = line3DOverlay->getEndParentID();
|
||||
_endParentJointIndex = line3DOverlay->getEndJointIndex();
|
||||
_lineWidth = line3DOverlay->getLineWidth();
|
||||
_glow = line3DOverlay->getGlow();
|
||||
_glowWidth = line3DOverlay->getGlowWidth();
|
||||
}
|
||||
|
||||
Line3DOverlay::~Line3DOverlay() {
|
||||
|
@ -145,7 +145,7 @@ void Line3DOverlay::render(RenderArgs* args) {
|
|||
geometryCache->renderDashedLine(*batch, start, end, colorv4, _geometryCacheID);
|
||||
} else {
|
||||
// renderGlowLine handles both glow = 0 and glow > 0 cases
|
||||
geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _geometryCacheID);
|
||||
geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _lineWidth, _geometryCacheID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,11 +239,10 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
|||
}
|
||||
}
|
||||
|
||||
auto glowWidth = properties["glowWidth"];
|
||||
if (glowWidth.isValid()) {
|
||||
setGlowWidth(glowWidth.toFloat());
|
||||
auto lineWidth = properties["lineWidth"];
|
||||
if (lineWidth.isValid()) {
|
||||
setLineWidth(lineWidth.toFloat());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QVariant Line3DOverlay::getProperty(const QString& property) {
|
||||
|
@ -262,6 +261,9 @@ QVariant Line3DOverlay::getProperty(const QString& property) {
|
|||
if (property == "length") {
|
||||
return QVariant(getLength());
|
||||
}
|
||||
if (property == "lineWidth") {
|
||||
return _lineWidth;
|
||||
}
|
||||
|
||||
return Base3DOverlay::getProperty(property);
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ public:
|
|||
// getters
|
||||
glm::vec3 getStart() const;
|
||||
glm::vec3 getEnd() const;
|
||||
const float& getLineWidth() const { return _lineWidth; }
|
||||
const float& getGlow() const { return _glow; }
|
||||
const float& getGlowWidth() const { return _glowWidth; }
|
||||
|
||||
// setters
|
||||
void setStart(const glm::vec3& start);
|
||||
|
@ -41,8 +41,8 @@ public:
|
|||
void setLocalStart(const glm::vec3& localStart) { setLocalPosition(localStart); }
|
||||
void setLocalEnd(const glm::vec3& localEnd);
|
||||
|
||||
void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; }
|
||||
void setGlow(const float& glow) { _glow = glow; }
|
||||
void setGlowWidth(const float& glowWidth) { _glowWidth = glowWidth; }
|
||||
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
|
@ -70,8 +70,9 @@ private:
|
|||
glm::vec3 _direction; // in parent frame
|
||||
float _length { 1.0 }; // in parent frame
|
||||
|
||||
const float DEFAULT_LINE_WIDTH = 0.02f;
|
||||
float _lineWidth { DEFAULT_LINE_WIDTH };
|
||||
float _glow { 0.0 };
|
||||
float _glowWidth { 0.0 };
|
||||
int _geometryCacheID;
|
||||
};
|
||||
|
||||
|
|
|
@ -179,6 +179,11 @@ void Rig::restoreRoleAnimation(const QString& role) {
|
|||
} else {
|
||||
qCWarning(animation) << "Rig::restoreRoleAnimation could not find role " << role;
|
||||
}
|
||||
|
||||
auto statesIter = _roleAnimStates.find(role);
|
||||
if (statesIter != _roleAnimStates.end()) {
|
||||
_roleAnimStates.erase(statesIter);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCWarning(animation) << "Rig::overrideRoleAnimation avatar not ready yet";
|
||||
|
|
|
@ -1579,7 +1579,7 @@ float Avatar::getEyeHeight() const {
|
|||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
float result = DEFAULT_AVATAR_EYE_HEIGHT;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getHeight", Q_RETURN_ARG(float, result));
|
||||
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getEyeHeight", Q_RETURN_ARG(float, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,22 +40,26 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity
|
|||
if (_stage) {
|
||||
if (!LightStage::isIndexInvalid(_sunIndex)) {
|
||||
_stage->removeLight(_sunIndex);
|
||||
_sunIndex = INVALID_INDEX;
|
||||
_shadowIndex = INVALID_INDEX;
|
||||
}
|
||||
if (!LightStage::isIndexInvalid(_ambientIndex)) {
|
||||
_stage->removeLight(_ambientIndex);
|
||||
|
||||
_ambientIndex = INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
if (_backgroundStage) {
|
||||
if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) {
|
||||
_backgroundStage->removeBackground(_backgroundIndex);
|
||||
_backgroundIndex = INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
if (_hazeStage) {
|
||||
if (!HazeStage::isIndexInvalid(_hazeIndex)) {
|
||||
_hazeStage->removeHaze(_hazeIndex);
|
||||
_hazeIndex = INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
if (diameter > MIN_DIAMETER
|
||||
&& fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
_collisionShapeType = SHAPE_TYPE_SPHERE;
|
||||
_collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
|
||||
} else if (hullShapeCalculator) {
|
||||
hullShapeCalculator(this, info);
|
||||
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
|
||||
|
|
19
libraries/gpu/src/gpu/DrawColor.slf
Normal file
19
libraries/gpu/src/gpu/DrawColor.slf
Normal file
|
@ -0,0 +1,19 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Draw with color uniform
|
||||
//
|
||||
// Created by Olivier Prat on 25/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
uniform vec4 color;
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = color;
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple...
|
||||
|
||||
#include "DrawWhite_frag.h"
|
||||
#include "DrawColor_frag.h"
|
||||
#include "DrawTexture_frag.h"
|
||||
#include "DrawTextureMirroredX_frag.h"
|
||||
#include "DrawTextureOpaque_frag.h"
|
||||
|
@ -37,6 +38,7 @@ ShaderPointer StandardShaderLib::_drawVertexPositionVS;
|
|||
ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
|
||||
ShaderPointer StandardShaderLib::_drawNadaPS;
|
||||
ShaderPointer StandardShaderLib::_drawWhitePS;
|
||||
ShaderPointer StandardShaderLib::_drawColorPS;
|
||||
ShaderPointer StandardShaderLib::_drawTexturePS;
|
||||
ShaderPointer StandardShaderLib::_drawTextureMirroredXPS;
|
||||
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
|
||||
|
@ -125,6 +127,13 @@ ShaderPointer StandardShaderLib::getDrawWhitePS() {
|
|||
return _drawWhitePS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawColorPS() {
|
||||
if (!_drawColorPS) {
|
||||
_drawColorPS = gpu::Shader::createPixel(std::string(DrawColor_frag));
|
||||
}
|
||||
return _drawColorPS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawTexturePS() {
|
||||
if (!_drawTexturePS) {
|
||||
_drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag));
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
static ShaderPointer getDrawNadaPS();
|
||||
|
||||
static ShaderPointer getDrawWhitePS();
|
||||
static ShaderPointer getDrawColorPS();
|
||||
static ShaderPointer getDrawTexturePS();
|
||||
static ShaderPointer getDrawTextureMirroredXPS();
|
||||
static ShaderPointer getDrawTextureOpaquePS();
|
||||
|
@ -67,6 +68,7 @@ protected:
|
|||
|
||||
static ShaderPointer _drawNadaPS;
|
||||
static ShaderPointer _drawWhitePS;
|
||||
static ShaderPointer _drawColorPS;
|
||||
static ShaderPointer _drawTexturePS;
|
||||
static ShaderPointer _drawTextureMirroredXPS;
|
||||
static ShaderPointer _drawTextureOpaquePS;
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <StatTracker.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "AccountManager.h"
|
||||
|
@ -1110,7 +1109,6 @@ void LimitedNodeList::setLocalSocket(const HifiSockAddr& sockAddr) {
|
|||
qCInfo(networking) << "Local socket is" << sockAddr;
|
||||
} else {
|
||||
qCInfo(networking) << "Local socket has changed from" << _localSockAddr << "to" << sockAddr;
|
||||
DependencyManager::get<StatTracker>()->incrementStat(LOCAL_SOCKET_CHANGE_STAT);
|
||||
}
|
||||
|
||||
_localSockAddr = sockAddr;
|
||||
|
|
|
@ -66,8 +66,6 @@ const QHostAddress DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME = QHostAddress::Lo
|
|||
|
||||
const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
|
||||
|
||||
const QString LOCAL_SOCKET_CHANGE_STAT = "LocalSocketChanges";
|
||||
|
||||
typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
|
||||
typedef tbb::concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
virtual ~OctreeQuery() {}
|
||||
|
||||
int getBroadcastData(unsigned char* destinationBuffer);
|
||||
int parseData(ReceivedMessage& message) override;
|
||||
virtual int parseData(ReceivedMessage& message) override;
|
||||
|
||||
// getters for camera details
|
||||
const glm::vec3& getCameraPosition() const { return _cameraPosition; }
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <UUID.h>
|
||||
|
||||
int OctreeQueryNode::parseData(ReceivedMessage& message) {
|
||||
// set our flag to indicate that we've parsed for this query at least once
|
||||
_hasReceivedFirstQuery = true;
|
||||
|
||||
return OctreeQuery::parseData(message);
|
||||
}
|
||||
|
||||
void OctreeQueryNode::nodeKilled() {
|
||||
_isShuttingDown = true;
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
void init(); // called after creation to set up some virtual items
|
||||
virtual PacketType getMyPacketType() const = 0;
|
||||
|
||||
virtual int parseData(ReceivedMessage& message) override;
|
||||
|
||||
void resetOctreePacket(); // resets octree packet to after "V" header
|
||||
|
||||
void writeToPacket(const unsigned char* buffer, unsigned int bytes); // writes to end of packet
|
||||
|
@ -106,6 +108,8 @@ public:
|
|||
bool shouldForceFullScene() const { return _shouldForceFullScene; }
|
||||
void setShouldForceFullScene(bool shouldForceFullScene) { _shouldForceFullScene = shouldForceFullScene; }
|
||||
|
||||
bool hasReceivedFirstQuery() const { return _hasReceivedFirstQuery; }
|
||||
|
||||
private:
|
||||
OctreeQueryNode(const OctreeQueryNode &);
|
||||
OctreeQueryNode& operator= (const OctreeQueryNode&);
|
||||
|
@ -153,6 +157,8 @@ private:
|
|||
QJsonObject _lastCheckJSONParameters;
|
||||
|
||||
bool _shouldForceFullScene { false };
|
||||
|
||||
bool _hasReceivedFirstQuery { false };
|
||||
};
|
||||
|
||||
#endif // hifi_OctreeQueryNode_h
|
||||
|
|
27
libraries/render-utils/src/BloomApply.slf
Normal file
27
libraries/render-utils/src/BloomApply.slf
Normal file
|
@ -0,0 +1,27 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// BloomApply.slf
|
||||
// Mix the three gaussian blur textures.
|
||||
//
|
||||
// Created by Olivier Prat on 10/09/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
uniform sampler2D blurMap0;
|
||||
uniform sampler2D blurMap1;
|
||||
uniform sampler2D blurMap2;
|
||||
uniform float intensity;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
vec4 blur0 = texture(blurMap0, varTexCoord0);
|
||||
vec4 blur1 = texture(blurMap1, varTexCoord0);
|
||||
vec4 blur2 = texture(blurMap2, varTexCoord0);
|
||||
|
||||
outFragColor = vec4((blur0.rgb+blur1.rgb+blur2.rgb)*intensity, 1.0f);
|
||||
}
|
359
libraries/render-utils/src/BloomEffect.cpp
Normal file
359
libraries/render-utils/src/BloomEffect.cpp
Normal file
|
@ -0,0 +1,359 @@
|
|||
//
|
||||
// BloomEffect.cpp
|
||||
// render-utils/src/
|
||||
//
|
||||
// Created by Olivier Prat on 09/25/17.
|
||||
// Copyright 2017 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 "BloomEffect.h"
|
||||
|
||||
#include "gpu/Context.h"
|
||||
#include "gpu/StandardShaderLib.h"
|
||||
|
||||
#include <render/BlurTask.h>
|
||||
#include <render/ResampleTask.h>
|
||||
|
||||
#include "BloomThreshold_frag.h"
|
||||
#include "BloomApply_frag.h"
|
||||
|
||||
#define BLOOM_BLUR_LEVEL_COUNT 3
|
||||
|
||||
BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) :
|
||||
_downsamplingFactor(downsamplingFactor) {
|
||||
assert(downsamplingFactor > 0);
|
||||
}
|
||||
|
||||
void BloomThreshold::configure(const Config& config) {
|
||||
_threshold = config.threshold;
|
||||
}
|
||||
|
||||
void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto frameTransform = inputs.get0();
|
||||
const auto inputFrameBuffer = inputs.get1();
|
||||
|
||||
assert(inputFrameBuffer->hasColor());
|
||||
|
||||
auto inputBuffer = inputFrameBuffer->getRenderBuffer(0);
|
||||
auto bufferSize = gpu::Vec2u(inputBuffer->getDimensions());
|
||||
|
||||
// Downsample resolution
|
||||
bufferSize.x /= _downsamplingFactor;
|
||||
bufferSize.y /= _downsamplingFactor;
|
||||
|
||||
if (!_outputBuffer || _outputBuffer->getSize() != bufferSize) {
|
||||
auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputBuffer->getTexelFormat(), bufferSize.x, bufferSize.y,
|
||||
gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
|
||||
|
||||
_outputBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold"));
|
||||
_outputBuffer->setRenderBuffer(0, colorTexture);
|
||||
}
|
||||
|
||||
static const int COLOR_MAP_SLOT = 0;
|
||||
static const int THRESHOLD_SLOT = 1;
|
||||
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("colorMap", COLOR_MAP_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding("threshold", THRESHOLD_SLOT));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y };
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport));
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
batch.setFramebuffer(_outputBuffer);
|
||||
batch.setResourceTexture(COLOR_MAP_SLOT, inputBuffer);
|
||||
batch._glUniform1f(THRESHOLD_SLOT, _threshold);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
|
||||
outputs = _outputBuffer;
|
||||
}
|
||||
|
||||
BloomApply::BloomApply() {
|
||||
|
||||
}
|
||||
|
||||
void BloomApply::configure(const Config& config) {
|
||||
_intensity = config.intensity;
|
||||
}
|
||||
|
||||
void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
static auto BLUR0_SLOT = 0;
|
||||
static auto BLUR1_SLOT = 1;
|
||||
static auto BLUR2_SLOT = 2;
|
||||
static auto INTENSITY_SLOT = 3;
|
||||
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(BloomApply_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("blurMap0", BLUR0_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding("blurMap1", BLUR1_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding("blurMap2", BLUR2_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding("intensity", INTENSITY_SLOT));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
const auto frameBuffer = inputs.get0();
|
||||
const auto framebufferSize = frameBuffer->getSize();
|
||||
const auto blur0FB = inputs.get1();
|
||||
const auto blur1FB = inputs.get2();
|
||||
const auto blur2FB = inputs.get3();
|
||||
const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y };
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setFramebuffer(frameBuffer);
|
||||
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport));
|
||||
batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0));
|
||||
batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0));
|
||||
batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0));
|
||||
batch._glUniform1f(INTENSITY_SLOT, _intensity / 3.0f);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
||||
void BloomDraw::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto frameBuffer = inputs.get0();
|
||||
const auto bloomFrameBuffer = inputs.get1();
|
||||
|
||||
if (frameBuffer && bloomFrameBuffer) {
|
||||
const auto framebufferSize = frameBuffer->getSize();
|
||||
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||
state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
|
||||
gpu::State::ZERO, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setFramebuffer(frameBuffer);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||
batch.setResourceTexture(0, bloomFrameBuffer->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
DebugBloom::DebugBloom() {
|
||||
}
|
||||
|
||||
void DebugBloom::configure(const Config& config) {
|
||||
_mode = static_cast<DebugBloomConfig::Mode>(config.mode);
|
||||
assert(_mode < DebugBloomConfig::MODE_COUNT);
|
||||
}
|
||||
|
||||
void DebugBloom::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto frameBuffer = inputs.get0();
|
||||
const auto combinedBlurBuffer = inputs.get4();
|
||||
const auto framebufferSize = frameBuffer->getSize();
|
||||
const auto level0FB = inputs.get1();
|
||||
const auto level1FB = inputs.get2();
|
||||
const auto level2FB = inputs.get3();
|
||||
const gpu::TexturePointer levelTextures[BLOOM_BLUR_LEVEL_COUNT] = {
|
||||
level0FB->getRenderBuffer(0),
|
||||
level1FB->getRenderBuffer(0),
|
||||
level2FB->getRenderBuffer(0)
|
||||
};
|
||||
|
||||
static auto TEXCOORD_RECT_SLOT = 1;
|
||||
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("texcoordRect"), TEXCOORD_RECT_SLOT));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setFramebuffer(frameBuffer);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
Transform modelTransform;
|
||||
if (_mode == DebugBloomConfig::MODE_ALL_LEVELS) {
|
||||
batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.0f, 0.0f, 1.f, 1.f);
|
||||
|
||||
modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2);
|
||||
modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f));
|
||||
batch.setModelTransform(modelTransform);
|
||||
batch.setResourceTexture(0, levelTextures[0]);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
modelTransform.postTranslate(glm::vec3(2.0f, 0.0f, 0.0f));
|
||||
batch.setModelTransform(modelTransform);
|
||||
batch.setResourceTexture(0, levelTextures[1]);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
modelTransform.postTranslate(glm::vec3(-2.0f, -2.0f, 0.0f));
|
||||
batch.setModelTransform(modelTransform);
|
||||
batch.setResourceTexture(0, levelTextures[2]);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
modelTransform.postTranslate(glm::vec3(2.0f, 0.0f, 0.0f));
|
||||
batch.setModelTransform(modelTransform);
|
||||
batch.setResourceTexture(0, combinedBlurBuffer->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
} else {
|
||||
auto viewport = args->_viewport;
|
||||
auto blurLevel = _mode - DebugBloomConfig::MODE_LEVEL0;
|
||||
|
||||
viewport.z /= 2;
|
||||
|
||||
batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f, 0.0f, 0.5f, 1.f);
|
||||
|
||||
modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport);
|
||||
modelTransform.postTranslate(glm::vec3(-1.0f, 0.0f, 0.0f));
|
||||
batch.setModelTransform(modelTransform);
|
||||
batch.setResourceTexture(0, levelTextures[blurLevel]);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BloomConfig::setIntensity(float value) {
|
||||
auto task = static_cast<render::Task::TaskConcept*>(_task);
|
||||
auto blurJobIt = task->editJob("BloomApply");
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
blurJobIt->getConfiguration()->setProperty("intensity", value);
|
||||
}
|
||||
|
||||
float BloomConfig::getIntensity() const {
|
||||
auto task = static_cast<render::Task::TaskConcept*>(_task);
|
||||
auto blurJobIt = task->getJob("BloomApply");
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
return blurJobIt->getConfiguration()->property("intensity").toFloat();
|
||||
}
|
||||
|
||||
void BloomConfig::setSize(float value) {
|
||||
std::string blurName{ "BloomBlurN" };
|
||||
auto sigma = 0.5f+value*3.5f;
|
||||
|
||||
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
|
||||
blurName.back() = '0' + i;
|
||||
auto task = static_cast<render::Task::TaskConcept*>(_task);
|
||||
auto blurJobIt = task->editJob(blurName);
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
auto& gaussianBlur = blurJobIt->edit<render::BlurGaussian>();
|
||||
auto gaussianBlurParams = gaussianBlur.getParameters();
|
||||
gaussianBlurParams->setFilterGaussianTaps(5, sigma);
|
||||
// Gaussian blur increases at each level to have a slower rolloff on the edge
|
||||
// of the response
|
||||
sigma *= 1.5f;
|
||||
}
|
||||
}
|
||||
|
||||
Bloom::Bloom() {
|
||||
|
||||
}
|
||||
|
||||
void Bloom::configure(const Config& config) {
|
||||
std::string blurName{ "BloomBlurN" };
|
||||
|
||||
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
|
||||
blurName.back() = '0' + i;
|
||||
auto blurConfig = config.getConfig<render::BlurGaussian>(blurName);
|
||||
blurConfig->setProperty("filterScale", 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
|
||||
// Start by computing threshold of color buffer input at quarter resolution
|
||||
const auto bloomInputBuffer = task.addJob<BloomThreshold>("BloomThreshold", inputs, 4U);
|
||||
|
||||
// Multi-scale blur, each new blur is half resolution of the previous pass
|
||||
const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", bloomInputBuffer, true);
|
||||
const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", blurFB0, true, 2U);
|
||||
const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", blurFB1, true, 2U);
|
||||
|
||||
const auto& input = inputs.get<Inputs>();
|
||||
const auto& frameBuffer = input[1];
|
||||
|
||||
// Mix all blur levels at quarter resolution
|
||||
const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2).asVarying();
|
||||
task.addJob<BloomApply>("BloomApply", applyInput);
|
||||
// And them blend result in additive manner on top of final color buffer
|
||||
const auto drawInput = BloomDraw::Inputs(frameBuffer, bloomInputBuffer).asVarying();
|
||||
task.addJob<BloomDraw>("BloomDraw", drawInput);
|
||||
|
||||
const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2, bloomInputBuffer).asVarying();
|
||||
task.addJob<DebugBloom>("DebugBloom", debugInput);
|
||||
}
|
166
libraries/render-utils/src/BloomEffect.h
Normal file
166
libraries/render-utils/src/BloomEffect.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
// BloomEffect.h
|
||||
// render-utils/src/
|
||||
//
|
||||
// Created by Olivier Prat on 09/25/17.
|
||||
// Copyright 2017 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_render_utils_BloomEffect_h
|
||||
#define hifi_render_utils_BloomEffect_h
|
||||
|
||||
#include <render/Engine.h>
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
||||
class BloomConfig : public render::Task::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty)
|
||||
Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
BloomConfig() : render::Task::Config(false) {}
|
||||
|
||||
float size{ 0.8f };
|
||||
|
||||
void setIntensity(float value);
|
||||
float getIntensity() const;
|
||||
void setSize(float value);
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class BloomThresholdConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
float threshold{ 1.25f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class BloomThreshold {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>;
|
||||
using Outputs = gpu::FramebufferPointer;
|
||||
using Config = BloomThresholdConfig;
|
||||
using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
|
||||
|
||||
BloomThreshold(unsigned int downsamplingFactor);
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
||||
|
||||
private:
|
||||
|
||||
gpu::FramebufferPointer _outputBuffer;
|
||||
gpu::PipelinePointer _pipeline;
|
||||
float _threshold;
|
||||
unsigned int _downsamplingFactor;
|
||||
};
|
||||
|
||||
|
||||
class BloomApplyConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
float intensity{ 0.8f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class BloomApply {
|
||||
public:
|
||||
using Inputs = render::VaryingSet4<gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer>;
|
||||
using Config = BloomApplyConfig;
|
||||
using JobModel = render::Job::ModelI<BloomApply, Inputs, Config>;
|
||||
|
||||
BloomApply();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
private:
|
||||
|
||||
gpu::PipelinePointer _pipeline;
|
||||
float _intensity{ 1.0f };
|
||||
};
|
||||
|
||||
class BloomDraw {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2<gpu::FramebufferPointer, gpu::FramebufferPointer>;
|
||||
using JobModel = render::Job::ModelI<BloomDraw, Inputs>;
|
||||
|
||||
BloomDraw() {}
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
private:
|
||||
|
||||
gpu::PipelinePointer _pipeline;
|
||||
};
|
||||
|
||||
class DebugBloomConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int mode MEMBER mode NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
enum Mode {
|
||||
MODE_LEVEL0 = 0,
|
||||
MODE_LEVEL1,
|
||||
MODE_LEVEL2,
|
||||
MODE_ALL_LEVELS,
|
||||
|
||||
MODE_COUNT
|
||||
};
|
||||
|
||||
DebugBloomConfig() : render::Job::Config(false) {}
|
||||
|
||||
int mode{ MODE_ALL_LEVELS };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class DebugBloom {
|
||||
public:
|
||||
using Inputs = render::VaryingSet5<gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer>;
|
||||
using Config = DebugBloomConfig;
|
||||
using JobModel = render::Job::ModelI<DebugBloom, Inputs, Config>;
|
||||
|
||||
DebugBloom();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
private:
|
||||
gpu::PipelinePointer _pipeline;
|
||||
DebugBloomConfig::Mode _mode;
|
||||
};
|
||||
|
||||
class Bloom {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>;
|
||||
using Config = BloomConfig;
|
||||
using JobModel = render::Task::ModelI<Bloom, Inputs, Config>;
|
||||
|
||||
Bloom();
|
||||
|
||||
void configure(const Config& config);
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_render_utils_BloomEffect_h
|
45
libraries/render-utils/src/BloomThreshold.slf
Normal file
45
libraries/render-utils/src/BloomThreshold.slf
Normal file
|
@ -0,0 +1,45 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// BloomThreshold.slf
|
||||
// Perform a soft threshold on an input texture and downsample to half size in one go.
|
||||
//
|
||||
// Created by Olivier Prat on 09/26/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
uniform float threshold;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
#define DOWNSAMPLING_FACTOR 4
|
||||
#define SAMPLE_COUNT (DOWNSAMPLING_FACTOR/2)
|
||||
|
||||
void main(void) {
|
||||
vec2 deltaX = dFdx(varTexCoord0) / SAMPLE_COUNT;
|
||||
vec2 deltaY = dFdy(varTexCoord0) / SAMPLE_COUNT;
|
||||
vec2 startUv = varTexCoord0;
|
||||
vec4 maskedColor = vec4(0,0,0,0);
|
||||
|
||||
for (int y=0 ; y<SAMPLE_COUNT ; y++) {
|
||||
vec2 uv = startUv;
|
||||
|
||||
for (int x=0 ; x<SAMPLE_COUNT ; x++) {
|
||||
vec4 color = texture(colorMap, uv);
|
||||
float luminance = (color.r+color.g+color.b) / 3.0;
|
||||
float mask = clamp((luminance-threshold)*0.25, 0, 1);
|
||||
|
||||
color *= mask;
|
||||
maskedColor += color;
|
||||
uv += deltaX;
|
||||
}
|
||||
|
||||
startUv += deltaY;
|
||||
}
|
||||
maskedColor /= SAMPLE_COUNT*SAMPLE_COUNT;
|
||||
outFragColor = vec4(maskedColor.rgb, 1.0);
|
||||
}
|
|
@ -73,9 +73,9 @@ void DeferredFramebuffer::allocate() {
|
|||
_deferredFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
|
||||
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
|
||||
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
||||
|
||||
_lightingTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, defaultSampler);
|
||||
_lightingTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, smoothSampler);
|
||||
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("lighting"));
|
||||
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
|
||||
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
|
|
@ -105,13 +105,13 @@ void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Bat
|
|||
PerformanceTimer perfTimer("DLE->setupBatch()");
|
||||
model::LightPointer keySunLight;
|
||||
auto lightStage = args->_scene->getStage<LightStage>();
|
||||
if (lightStage && lightStage->_currentFrame._sunLights.size()) {
|
||||
keySunLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front());
|
||||
if (lightStage) {
|
||||
keySunLight = lightStage->getCurrentKeyLight();
|
||||
}
|
||||
|
||||
model::LightPointer keyAmbiLight;
|
||||
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
|
||||
keyAmbiLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front());
|
||||
if (lightStage) {
|
||||
keyAmbiLight = lightStage->getCurrentAmbientLight();
|
||||
}
|
||||
|
||||
if (keySunLight) {
|
||||
|
@ -620,7 +620,7 @@ void RenderDeferredLocals::run(const render::RenderContextPointer& renderContext
|
|||
auto& lightIndices = lightClusters->_visibleLightIndices;
|
||||
if (!lightIndices.empty() && lightIndices[0] > 0) {
|
||||
// Bind the global list of lights and the visible lights this frame
|
||||
batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->_lightArrayBuffer);
|
||||
batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->getLightArrayBuffer());
|
||||
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
|
||||
|
|
|
@ -175,9 +175,9 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
|
|||
batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer());
|
||||
|
||||
auto lightStage = args->_scene->getStage<LightStage>();
|
||||
if (lightStage && lightStage->_currentFrame._sunLights.size() > 0) {
|
||||
model::LightPointer keyLight;
|
||||
keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front());
|
||||
if (lightStage) {
|
||||
model::LightPointer keyLight;
|
||||
keyLight = lightStage->getCurrentKeyLight();
|
||||
if (keyLight != nullptr) {
|
||||
batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer());
|
||||
}
|
||||
|
|
|
@ -1931,9 +1931,10 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
|
|||
vec4 p1;
|
||||
vec4 p2;
|
||||
vec4 color;
|
||||
float width;
|
||||
};
|
||||
|
||||
LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color };
|
||||
LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color, glowWidth };
|
||||
details.uniformBuffer->resize(sizeof(LineData));
|
||||
details.uniformBuffer->setSubData(0, lineData);
|
||||
}
|
||||
|
|
|
@ -727,7 +727,7 @@ void DebugLightClusters::run(const render::RenderContextPointer& renderContext,
|
|||
batch.setModelTransform(Transform());
|
||||
|
||||
// Bind the Light CLuster data strucutre
|
||||
batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->_lightArrayBuffer);
|
||||
batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->getLightArrayBuffer());
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer);
|
||||
|
|
|
@ -19,14 +19,29 @@ const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::I
|
|||
LightStage::LightStage() {
|
||||
}
|
||||
|
||||
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
|
||||
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
|
||||
map = framebuffer->getDepthStencilBuffer();
|
||||
Schema schema;
|
||||
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
||||
LightStage::Shadow::Schema::Schema() :
|
||||
bias{ 0.005f },
|
||||
scale{ 1.0f / MAP_SIZE } {
|
||||
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth) {
|
||||
gpu::FramebufferPointer LightStage::Shadow::framebuffer;
|
||||
gpu::TexturePointer LightStage::Shadow::map;
|
||||
|
||||
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
|
||||
Schema schema;
|
||||
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
||||
|
||||
if (!framebuffer) {
|
||||
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
|
||||
map = framebuffer->getDepthStencilBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum,
|
||||
float viewMinShadowDistance, float viewMaxShadowDistance,
|
||||
float nearDepth, float farDepth) {
|
||||
assert(viewMinShadowDistance < viewMaxShadowDistance);
|
||||
assert(nearDepth < farDepth);
|
||||
|
||||
// Orient the keylight frustum
|
||||
|
@ -49,8 +64,8 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa
|
|||
const Transform view{ _frustum->getView()};
|
||||
const Transform viewInverse{ view.getInverseMatrix() };
|
||||
|
||||
auto nearCorners = viewFrustum.getCorners(nearDepth);
|
||||
auto farCorners = viewFrustum.getCorners(farDepth);
|
||||
auto nearCorners = viewFrustum.getCorners(viewMinShadowDistance);
|
||||
auto farCorners = viewFrustum.getCorners(viewMaxShadowDistance);
|
||||
|
||||
vec3 min{ viewInverse.transform(nearCorners.bottomLeft) };
|
||||
vec3 max{ min };
|
||||
|
@ -74,7 +89,10 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa
|
|||
fitFrustum(farCorners.topLeft);
|
||||
fitFrustum(farCorners.topRight);
|
||||
|
||||
glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, -max.z, -min.z);
|
||||
// Re-adjust near shadow distance
|
||||
auto near = glm::max(max.z, -nearDepth);
|
||||
auto far = -min.z;
|
||||
glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, near, far);
|
||||
_frustum->setProjection(ortho);
|
||||
|
||||
// Calculate the frustum's internal state
|
||||
|
@ -85,6 +103,16 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa
|
|||
_schemaBuffer.edit<Schema>().viewInverse = viewInverse.getMatrix();
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setFrustum(const ViewFrustum& shadowFrustum) {
|
||||
const Transform view{ shadowFrustum.getView() };
|
||||
const Transform viewInverse{ view.getInverseMatrix() };
|
||||
|
||||
*_frustum = shadowFrustum;
|
||||
// Update the buffer
|
||||
_schemaBuffer.edit<Schema>().projection = shadowFrustum.getProjection();
|
||||
_schemaBuffer.edit<Schema>().viewInverse = viewInverse.getMatrix();
|
||||
}
|
||||
|
||||
const glm::mat4& LightStage::Shadow::getView() const {
|
||||
return _frustum->getView();
|
||||
}
|
||||
|
@ -100,11 +128,9 @@ LightStage::Index LightStage::findLight(const LightPointer& light) const {
|
|||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LightStage::Index LightStage::addLight(const LightPointer& light) {
|
||||
|
||||
auto found = _lightMap.find(light);
|
||||
if (found == _lightMap.end()) {
|
||||
auto lightId = _lights.newElement(light);
|
||||
|
@ -115,6 +141,7 @@ LightStage::Index LightStage::addLight(const LightPointer& light) {
|
|||
if (lightId >= (Index) _descs.size()) {
|
||||
_descs.emplace_back(Desc());
|
||||
} else {
|
||||
assert(_descs[lightId].shadowId == INVALID_INDEX);
|
||||
_descs.emplace(_descs.begin() + lightId, Desc());
|
||||
}
|
||||
|
||||
|
@ -133,6 +160,7 @@ LightStage::Index LightStage::addShadow(Index lightIndex) {
|
|||
auto light = getLight(lightIndex);
|
||||
Index shadowId = INVALID_INDEX;
|
||||
if (light) {
|
||||
assert(_descs[lightIndex].shadowId == INVALID_INDEX);
|
||||
shadowId = _shadows.newElement(std::make_shared<Shadow>(light));
|
||||
_descs[lightIndex].shadowId = shadowId;
|
||||
}
|
||||
|
@ -140,18 +168,65 @@ LightStage::Index LightStage::addShadow(Index lightIndex) {
|
|||
}
|
||||
|
||||
LightStage::LightPointer LightStage::removeLight(Index index) {
|
||||
LightPointer removed = _lights.freeElement(index);
|
||||
|
||||
if (removed) {
|
||||
LightPointer removedLight = _lights.freeElement(index);
|
||||
if (removedLight) {
|
||||
auto shadowId = _descs[index].shadowId;
|
||||
// Remove shadow if one exists for this light
|
||||
if (shadowId != INVALID_INDEX) {
|
||||
_shadows.freeElement(shadowId);
|
||||
auto removedShadow = _shadows.freeElement(shadowId);
|
||||
assert(removedShadow);
|
||||
assert(removedShadow->getLight() == removedLight);
|
||||
}
|
||||
_lightMap.erase(removed);
|
||||
_lightMap.erase(removedLight);
|
||||
_descs[index] = Desc();
|
||||
}
|
||||
return removed;
|
||||
assert(_descs.size() <= index || _descs[index].shadowId == INVALID_INDEX);
|
||||
return removedLight;
|
||||
}
|
||||
|
||||
LightStage::LightPointer LightStage::getCurrentKeyLight() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return _lights.get(keyLightId);
|
||||
}
|
||||
|
||||
LightStage::LightPointer LightStage::getCurrentAmbientLight() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._ambientLights.empty()) {
|
||||
keyLightId = _currentFrame._ambientLights.front();
|
||||
}
|
||||
return _lights.get(keyLightId);
|
||||
}
|
||||
|
||||
LightStage::ShadowPointer LightStage::getCurrentKeyShadow() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
auto shadow = getShadow(keyLightId);
|
||||
assert(shadow == nullptr || shadow->getLight() == getLight(keyLightId));
|
||||
return shadow;
|
||||
}
|
||||
|
||||
LightStage::LightAndShadow LightStage::getCurrentKeyLightAndShadow() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
auto shadow = getShadow(keyLightId);
|
||||
auto light = getLight(keyLightId);
|
||||
assert(shadow == nullptr || shadow->getLight() == light);
|
||||
return LightAndShadow(light, shadow);
|
||||
}
|
||||
|
||||
LightStage::Index LightStage::getShadowId(Index lightId) const {
|
||||
if (checkLightId(lightId)) {
|
||||
return _descs[lightId].shadowId;
|
||||
} else {
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
void LightStage::updateLightArrayBuffer(Index lightId) {
|
||||
|
|
|
@ -48,8 +48,9 @@ public:
|
|||
|
||||
Shadow(model::LightPointer light);
|
||||
|
||||
void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth);
|
||||
void setKeylightFrustum(const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth = 1.0f, float farDepth = 1000.0f);
|
||||
|
||||
void setFrustum(const ViewFrustum& shadowFrustum);
|
||||
const std::shared_ptr<ViewFrustum> getFrustum() const { return _frustum; }
|
||||
|
||||
const glm::mat4& getView() const;
|
||||
|
@ -57,32 +58,36 @@ public:
|
|||
|
||||
const UniformBufferView& getBuffer() const { return _schemaBuffer; }
|
||||
|
||||
gpu::FramebufferPointer framebuffer;
|
||||
gpu::TexturePointer map;
|
||||
// Shadow maps are shared among all lights for the moment as only one key light
|
||||
// is used.
|
||||
static gpu::FramebufferPointer framebuffer;
|
||||
static gpu::TexturePointer map;
|
||||
|
||||
const model::LightPointer& getLight() const { return _light; }
|
||||
|
||||
protected:
|
||||
|
||||
model::LightPointer _light;
|
||||
std::shared_ptr<ViewFrustum> _frustum;
|
||||
|
||||
class Schema {
|
||||
public:
|
||||
|
||||
Schema();
|
||||
|
||||
glm::mat4 projection;
|
||||
glm::mat4 viewInverse;
|
||||
|
||||
glm::float32 bias = 0.005f;
|
||||
glm::float32 scale = 1 / MAP_SIZE;
|
||||
glm::float32 bias;
|
||||
glm::float32 scale;
|
||||
};
|
||||
UniformBufferView _schemaBuffer = nullptr;
|
||||
|
||||
friend class Light;
|
||||
};
|
||||
|
||||
using ShadowPointer = std::shared_ptr<Shadow>;
|
||||
using Shadows = render::indexed_container::IndexedPointerVector<Shadow>;
|
||||
|
||||
struct Desc {
|
||||
Index shadowId { INVALID_INDEX };
|
||||
};
|
||||
using Descs = std::vector<Desc>;
|
||||
|
||||
Index findLight(const LightPointer& light) const;
|
||||
Index addLight(const LightPointer& light);
|
||||
|
||||
|
@ -100,50 +105,29 @@ public:
|
|||
return _lights.get(lightId);
|
||||
}
|
||||
|
||||
Index getShadowId(Index lightId) const {
|
||||
if (checkLightId(lightId)) {
|
||||
return _descs[lightId].shadowId;
|
||||
} else {
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
Index getShadowId(Index lightId) const;
|
||||
|
||||
ShadowPointer getShadow(Index lightId) const {
|
||||
return _shadows.get(getShadowId(lightId));
|
||||
}
|
||||
|
||||
using LightAndShadow = std::pair<LightPointer, ShadowPointer>;
|
||||
LightAndShadow getLightAndShadow(Index lightId) const {
|
||||
return LightAndShadow(getLight(lightId), getShadow(lightId));
|
||||
auto light = getLight(lightId);
|
||||
auto shadow = getShadow(lightId);
|
||||
assert(shadow == nullptr || shadow->getLight() == light);
|
||||
return LightAndShadow(light, shadow);
|
||||
}
|
||||
|
||||
LightPointer getCurrentKeyLight() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return _lights.get(keyLightId);
|
||||
}
|
||||
|
||||
ShadowPointer getCurrentKeyShadow() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return getShadow(keyLightId);
|
||||
}
|
||||
|
||||
LightAndShadow getCurrentKeyLightAndShadow() const {
|
||||
Index keyLightId{ 0 };
|
||||
if (!_currentFrame._sunLights.empty()) {
|
||||
keyLightId = _currentFrame._sunLights.front();
|
||||
}
|
||||
return LightAndShadow(getLight(keyLightId), getShadow(keyLightId));
|
||||
}
|
||||
LightPointer getCurrentKeyLight() const;
|
||||
LightPointer getCurrentAmbientLight() const;
|
||||
ShadowPointer getCurrentKeyShadow() const;
|
||||
LightAndShadow getCurrentKeyLightAndShadow() const;
|
||||
|
||||
LightStage();
|
||||
Lights _lights;
|
||||
LightMap _lightMap;
|
||||
Descs _descs;
|
||||
|
||||
gpu::BufferPointer getLightArrayBuffer() const { return _lightArrayBuffer; }
|
||||
void updateLightArrayBuffer(Index lightId);
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
|
@ -172,15 +156,24 @@ public:
|
|||
|
||||
Frame _currentFrame;
|
||||
|
||||
gpu::BufferPointer _lightArrayBuffer;
|
||||
void updateLightArrayBuffer(Index lightId);
|
||||
protected:
|
||||
|
||||
struct Desc {
|
||||
Index shadowId{ INVALID_INDEX };
|
||||
};
|
||||
using Descs = std::vector<Desc>;
|
||||
|
||||
gpu::BufferPointer _lightArrayBuffer;
|
||||
|
||||
Lights _lights;
|
||||
Shadows _shadows;
|
||||
Descs _descs;
|
||||
LightMap _lightMap;
|
||||
|
||||
};
|
||||
using LightStagePointer = std::shared_ptr<LightStage>;
|
||||
|
||||
|
||||
|
||||
class LightStageSetup {
|
||||
public:
|
||||
using JobModel = render::Job::Model<LightStageSetup>;
|
||||
|
|
|
@ -42,10 +42,9 @@
|
|||
#include "ToneMappingEffect.h"
|
||||
#include "SubsurfaceScattering.h"
|
||||
#include "DrawHaze.h"
|
||||
#include "BloomEffect.h"
|
||||
#include "HighlightEffect.h"
|
||||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace render;
|
||||
|
@ -168,7 +167,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying();
|
||||
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
|
||||
|
||||
// LIght Cluster Grid Debuging job
|
||||
// Light Cluster Grid Debuging job
|
||||
{
|
||||
const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).asVarying();
|
||||
task.addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
|
||||
|
@ -179,6 +178,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
|
||||
const auto toneAndPostRangeTimer = task.addJob<BeginGPURangeTimer>("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing");
|
||||
|
||||
// Add bloom
|
||||
const auto bloomInputs = Bloom::Inputs(deferredFrameTransform, lightingFramebuffer).asVarying();
|
||||
task.addJob<Bloom>("Bloom", bloomInputs);
|
||||
|
||||
// Lighting Buffer ready for tone mapping
|
||||
const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying();
|
||||
task.addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
|
||||
|
@ -193,13 +196,18 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
|
||||
task.addJob<EndGPURangeTimer>("HighlightRangeTimer", outlineRangeTimer);
|
||||
|
||||
{ // DEbug the bounds of the rendered items, still look at the zbuffer
|
||||
{ // Debug the bounds of the rendered items, still look at the zbuffer
|
||||
task.addJob<DrawBounds>("DrawMetaBounds", metas);
|
||||
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
||||
|
||||
task.addJob<DrawBounds>("DrawLightBounds", lights);
|
||||
task.addJob<DrawBounds>("DrawZones", zones);
|
||||
const auto frustums = task.addJob<ExtractFrustums>("ExtractFrustums");
|
||||
const auto viewFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::VIEW_FRUSTUM);
|
||||
const auto shadowFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::SHADOW_FRUSTUM);
|
||||
task.addJob<DrawFrustum>("DrawViewFrustum", viewFrustum, glm::vec3(1.0f, 1.0f, 0.0f));
|
||||
task.addJob<DrawFrustum>("DrawShadowFrustum", shadowFrustum, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
|
||||
// Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true
|
||||
task.addJob<DrawBounds>("DrawSelectionBounds", selectedItems);
|
||||
|
@ -532,3 +540,32 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
|
|||
});
|
||||
}
|
||||
|
||||
void ExtractFrustums::run(const render::RenderContextPointer& renderContext, Output& output) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_context);
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
// Return view frustum
|
||||
auto& viewFrustum = output[VIEW_FRUSTUM].edit<ViewFrustumPointer>();
|
||||
if (!viewFrustum) {
|
||||
viewFrustum = std::make_shared<ViewFrustum>(args->getViewFrustum());
|
||||
} else {
|
||||
*viewFrustum = args->getViewFrustum();
|
||||
}
|
||||
|
||||
// Return shadow frustum
|
||||
auto& shadowFrustum = output[SHADOW_FRUSTUM].edit<ViewFrustumPointer>();
|
||||
auto lightStage = args->_scene->getStage<LightStage>(LightStage::getName());
|
||||
if (lightStage) {
|
||||
auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||
|
||||
if (globalShadow) {
|
||||
shadowFrustum = globalShadow->getFrustum();
|
||||
} else {
|
||||
shadowFrustum.reset();
|
||||
}
|
||||
} else {
|
||||
shadowFrustum.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,6 +170,22 @@ public:
|
|||
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
|
||||
};
|
||||
|
||||
class ExtractFrustums {
|
||||
public:
|
||||
|
||||
enum Frustum {
|
||||
VIEW_FRUSTUM,
|
||||
SHADOW_FRUSTUM,
|
||||
|
||||
FRUSTUM_COUNT
|
||||
};
|
||||
|
||||
using Output = render::VaryingArray<ViewFrustumPointer, FRUSTUM_COUNT>;
|
||||
using JobModel = render::Job::ModelO<ExtractFrustums, Output>;
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, Output& output);
|
||||
};
|
||||
|
||||
class RenderDeferredTaskConfig : public render::Task::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty)
|
||||
|
|
|
@ -22,25 +22,136 @@
|
|||
#include "DeferredLightingEffect.h"
|
||||
#include "FramebufferCache.h"
|
||||
|
||||
// These values are used for culling the objects rendered in the shadow map
|
||||
// but are readjusted afterwards
|
||||
#define SHADOW_FRUSTUM_NEAR 1.0f
|
||||
#define SHADOW_FRUSTUM_FAR 500.0f
|
||||
|
||||
using namespace render;
|
||||
|
||||
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state);
|
||||
|
||||
void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
|
||||
const render::ShapeBounds& inShapes) {
|
||||
static void computeNearFar(const Triangle& triangle, const Plane shadowClipPlanes[4], float& near, float& far) {
|
||||
static const int MAX_TRIANGLE_COUNT = 16;
|
||||
Triangle clippedTriangles[MAX_TRIANGLE_COUNT];
|
||||
auto clippedTriangleCount = clipTriangleWithPlanes(triangle, shadowClipPlanes, 4, clippedTriangles, MAX_TRIANGLE_COUNT);
|
||||
|
||||
for (auto i = 0; i < clippedTriangleCount; i++) {
|
||||
const auto& clippedTriangle = clippedTriangles[i];
|
||||
|
||||
near = glm::min(near, -clippedTriangle.v0.z);
|
||||
near = glm::min(near, -clippedTriangle.v1.z);
|
||||
near = glm::min(near, -clippedTriangle.v2.z);
|
||||
|
||||
far = glm::max(far, -clippedTriangle.v0.z);
|
||||
far = glm::max(far, -clippedTriangle.v1.z);
|
||||
far = glm::max(far, -clippedTriangle.v2.z);
|
||||
}
|
||||
}
|
||||
|
||||
static void computeNearFar(const glm::vec3 sceneBoundVertices[8], const Plane shadowClipPlanes[4], float& near, float& far) {
|
||||
// This code is inspired from Microsoft's CascadedShadowMaps11 sample which is under MIT licence.
|
||||
// See https://code.msdn.microsoft.com/windowsdesktop/Direct3D-Shadow-Win32-2d72a4f2/sourcecode?fileId=121915&pathId=1645833187
|
||||
// Basically it decomposes the object bounding box in triangles and clips each triangle with the shadow
|
||||
// frustum planes. Finally it computes the minimum and maximum depth of the clipped triangle vertices
|
||||
// in shadow space to extract the near and far distances of the shadow frustum.
|
||||
static const std::array<int[4], 6> boxQuadVertexIndices = { {
|
||||
{ TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR },
|
||||
{ TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR },
|
||||
{ TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR },
|
||||
{ TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR },
|
||||
{ BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_RIGHT_NEAR, BOTTOM_LEFT_NEAR },
|
||||
{ TOP_LEFT_FAR, TOP_RIGHT_FAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR }
|
||||
} };
|
||||
Triangle triangle;
|
||||
|
||||
for (auto quadVertexIndices : boxQuadVertexIndices) {
|
||||
triangle.v0 = sceneBoundVertices[quadVertexIndices[0]];
|
||||
triangle.v1 = sceneBoundVertices[quadVertexIndices[1]];
|
||||
triangle.v2 = sceneBoundVertices[quadVertexIndices[2]];
|
||||
computeNearFar(triangle, shadowClipPlanes, near, far);
|
||||
triangle.v1 = sceneBoundVertices[quadVertexIndices[3]];
|
||||
computeNearFar(triangle, shadowClipPlanes, near, far);
|
||||
}
|
||||
}
|
||||
|
||||
static void adjustNearFar(const AABox& inShapeBounds, ViewFrustum& shadowFrustum) {
|
||||
const Transform shadowView{ shadowFrustum.getView() };
|
||||
const Transform shadowViewInverse{ shadowView.getInverseMatrix() };
|
||||
|
||||
glm::vec3 sceneBoundVertices[8];
|
||||
// Keep only the left, right, top and bottom shadow frustum planes as we wish to determine
|
||||
// the near and far
|
||||
Plane shadowClipPlanes[4];
|
||||
int i;
|
||||
|
||||
// The vertices of the scene bounding box are expressed in the shadow frustum's local space
|
||||
for (i = 0; i < 8; i++) {
|
||||
sceneBoundVertices[i] = shadowViewInverse.transform(inShapeBounds.getVertex(static_cast<BoxVertex>(i)));
|
||||
}
|
||||
// This indirection array is just a protection in case the ViewFrustum::PlaneIndex enum
|
||||
// changes order especially as we don't need to test the NEAR and FAR planes.
|
||||
static const ViewFrustum::PlaneIndex planeIndices[4] = {
|
||||
ViewFrustum::TOP_PLANE,
|
||||
ViewFrustum::BOTTOM_PLANE,
|
||||
ViewFrustum::LEFT_PLANE,
|
||||
ViewFrustum::RIGHT_PLANE
|
||||
};
|
||||
// Same goes for the shadow frustum planes.
|
||||
for (i = 0; i < 4; i++) {
|
||||
const auto& worldPlane = shadowFrustum.getPlanes()[planeIndices[i]];
|
||||
// We assume the transform doesn't have a non uniform scale component to apply the
|
||||
// transform to the normal without using the correct transpose of inverse, which should be the
|
||||
// case for a view matrix.
|
||||
auto planeNormal = shadowViewInverse.transformDirection(worldPlane.getNormal());
|
||||
auto planePoint = shadowViewInverse.transform(worldPlane.getPoint());
|
||||
shadowClipPlanes[i].setNormalAndPoint(planeNormal, planePoint);
|
||||
}
|
||||
|
||||
float near = std::numeric_limits<float>::max();
|
||||
float far = 0.0f;
|
||||
|
||||
computeNearFar(sceneBoundVertices, shadowClipPlanes, near, far);
|
||||
// Limit the far range to the one used originally. There's no point in rendering objects
|
||||
// that are not in the view frustum.
|
||||
far = glm::min(far, shadowFrustum.getFarClip());
|
||||
|
||||
const auto depthEpsilon = 0.1f;
|
||||
auto projMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, near - depthEpsilon, far + depthEpsilon);
|
||||
auto shadowProjection = shadowFrustum.getProjection();
|
||||
|
||||
shadowProjection[2][2] = projMatrix[2][2];
|
||||
shadowProjection[3][2] = projMatrix[3][2];
|
||||
shadowFrustum.setProjection(shadowProjection);
|
||||
shadowFrustum.calculate();
|
||||
}
|
||||
|
||||
void RenderShadowMap::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
const auto& inShapes = inputs.get0();
|
||||
const auto& inShapeBounds = inputs.get1();
|
||||
|
||||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
||||
assert(lightStage);
|
||||
|
||||
const auto shadow = lightStage->getCurrentKeyShadow();
|
||||
auto shadow = lightStage->getCurrentKeyShadow();
|
||||
if (!shadow) return;
|
||||
|
||||
const auto& fbo = shadow->framebuffer;
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
ShapeKey::Builder defaultKeyBuilder;
|
||||
auto adjustedShadowFrustum = args->getViewFrustum();
|
||||
|
||||
// Adjust the frustum near and far depths based on the rendered items bounding box to have
|
||||
// the minimal Z range.
|
||||
adjustNearFar(inShapeBounds, adjustedShadowFrustum);
|
||||
// Reapply the frustum as it has been adjusted
|
||||
shadow->setFrustum(adjustedShadowFrustum);
|
||||
args->popViewFrustum();
|
||||
args->pushViewFrustum(adjustedShadowFrustum);
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
@ -55,8 +166,13 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
|
|||
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
|
||||
vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true);
|
||||
|
||||
batch.setProjectionTransform(shadow->getProjection());
|
||||
batch.setViewTransform(shadow->getView(), false);
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat, false);
|
||||
|
||||
auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
|
||||
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
|
||||
|
@ -87,7 +203,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
|
|||
}
|
||||
|
||||
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {
|
||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
|
||||
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; };
|
||||
|
||||
// Prepare the ShapePipeline
|
||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||
|
@ -109,10 +225,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
|
||||
// Sort
|
||||
const auto sortedPipelines = task.addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
|
||||
const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);
|
||||
const auto sortedShapesAndBounds = task.addJob<DepthSortShapesAndComputeBounds>("DepthSortShadowMap", sortedPipelines, true);
|
||||
|
||||
// GPU jobs: Render to shadow map
|
||||
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
||||
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapesAndBounds, shapePlumber);
|
||||
|
||||
task.addJob<RenderShadowTeardown>("ShadowTeardown", cachedMode);
|
||||
}
|
||||
|
@ -135,8 +251,8 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
|
||||
auto nearClip = args->getViewFrustum().getNearClip();
|
||||
float nearDepth = -args->_boomOffset.z;
|
||||
const int SHADOW_FAR_DEPTH = 20;
|
||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH);
|
||||
const float SHADOW_MAX_DISTANCE = 20.0f;
|
||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_MAX_DISTANCE, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
|
||||
// Set the keylight render args
|
||||
args->pushViewFrustum(*(globalShadow->getFrustum()));
|
||||
|
|
|
@ -21,11 +21,11 @@ class ViewFrustum;
|
|||
|
||||
class RenderShadowMap {
|
||||
public:
|
||||
using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapeBounds>;
|
||||
using Inputs = render::VaryingSet2<render::ShapeBounds, AABox>;
|
||||
using JobModel = render::Job::ModelI<RenderShadowMap, Inputs>;
|
||||
|
||||
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||
void run(const render::RenderContextPointer& renderContext,
|
||||
const render::ShapeBounds& inShapes);
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
render::ShapePlumberPointer _shapePlumber;
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
// auto items = input.get<Input>();
|
||||
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
// Shadows use an orthographic projection because they are linked to sunlights
|
||||
// but the cullFunctor passed is probably tailored for perspective projection and culls too much.
|
||||
// TODO : create a special cull functor for this.
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", nullptr);
|
||||
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
|
|
|
@ -68,6 +68,8 @@ vec2 PCFkernel[4] = vec2[4](
|
|||
);
|
||||
|
||||
float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) {
|
||||
// PCF is buggy so disable it for the time being
|
||||
#if 0
|
||||
float pcfRadius = 3.0;
|
||||
float shadowScale = getShadowScale();
|
||||
|
||||
|
@ -80,6 +82,9 @@ float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) {
|
|||
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[2], 0.0)) +
|
||||
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[3], 0.0))
|
||||
));
|
||||
#else
|
||||
float shadowAttenuation = fetchShadow(shadowTexcoord.xyz);
|
||||
#endif
|
||||
|
||||
return shadowAttenuation;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
//
|
||||
|
||||
in vec4 _color;
|
||||
in float distanceFromCenter;
|
||||
|
||||
in float distanceFromCenter;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
|
|
|
@ -16,6 +16,7 @@ layout(std140) uniform lineData {
|
|||
vec4 p1;
|
||||
vec4 p2;
|
||||
vec4 color;
|
||||
float width;
|
||||
};
|
||||
|
||||
out vec4 _color;
|
||||
|
@ -39,7 +40,7 @@ void main(void) {
|
|||
// Find the vector from the eye to one of the points
|
||||
vec3 v2 = normalize(p1eye.xyz);
|
||||
// The orthogonal vector is the cross product of these two
|
||||
vec3 orthogonal = cross(v1, v2) * 0.02;
|
||||
vec3 orthogonal = cross(v1, v2) * width;
|
||||
|
||||
// Deteremine which end to emit based on the vertex id (even / odd)
|
||||
vec4 eye = (0 == gl_VertexID % 2) ? p1eye : p2eye;
|
||||
|
|
|
@ -29,11 +29,10 @@ enum BlurShaderMapSlots {
|
|||
BlurTask_DepthSlot,
|
||||
};
|
||||
|
||||
const float BLUR_NUM_SAMPLES = 7.0f;
|
||||
|
||||
BlurParams::BlurParams() {
|
||||
Params params;
|
||||
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Params), (const gpu::Byte*) ¶ms));
|
||||
setFilterGaussianTaps(3);
|
||||
}
|
||||
|
||||
void BlurParams::setWidthHeight(int width, int height, bool isStereo) {
|
||||
|
@ -49,10 +48,10 @@ void BlurParams::setWidthHeight(int width, int height, bool isStereo) {
|
|||
}
|
||||
}
|
||||
|
||||
void BlurParams::setTexcoordTransform(const glm::vec4 texcoordTransformViewport) {
|
||||
auto texcoordTransform = _parametersBuffer.get<Params>().texcoordTransform;
|
||||
if (texcoordTransformViewport != texcoordTransform) {
|
||||
_parametersBuffer.edit<Params>().texcoordTransform = texcoordTransform;
|
||||
void BlurParams::setTexcoordTransform(glm::vec4 texcoordTransformViewport) {
|
||||
auto& params = _parametersBuffer.get<Params>();
|
||||
if (texcoordTransformViewport != params.texcoordTransform) {
|
||||
_parametersBuffer.edit<Params>().texcoordTransform = texcoordTransformViewport;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +59,58 @@ void BlurParams::setFilterRadiusScale(float scale) {
|
|||
auto filterInfo = _parametersBuffer.get<Params>().filterInfo;
|
||||
if (scale != filterInfo.x) {
|
||||
_parametersBuffer.edit<Params>().filterInfo.x = scale;
|
||||
_parametersBuffer.edit<Params>().filterInfo.y = scale / BLUR_NUM_SAMPLES;
|
||||
}
|
||||
}
|
||||
|
||||
void BlurParams::setFilterNumTaps(int count) {
|
||||
assert(count <= BLUR_MAX_NUM_TAPS);
|
||||
auto filterInfo = _parametersBuffer.get<Params>().filterInfo;
|
||||
if (count != (int)filterInfo.y) {
|
||||
_parametersBuffer.edit<Params>().filterInfo.y = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BlurParams::setFilterTap(int index, float offset, float value) {
|
||||
auto filterTaps = _parametersBuffer.edit<Params>().filterTaps;
|
||||
assert(index < BLUR_MAX_NUM_TAPS);
|
||||
filterTaps[index].x = offset;
|
||||
filterTaps[index].y = value;
|
||||
}
|
||||
|
||||
void BlurParams::setFilterGaussianTaps(int numHalfTaps, float sigma) {
|
||||
auto& params = _parametersBuffer.edit<Params>();
|
||||
const int numTaps = 2 * numHalfTaps + 1;
|
||||
assert(numTaps <= BLUR_MAX_NUM_TAPS);
|
||||
assert(sigma > 0.0f);
|
||||
const float inverseTwoSigmaSquared = float(0.5 / double(sigma*sigma));
|
||||
float totalWeight = 1.0f;
|
||||
float weight;
|
||||
float offset;
|
||||
int i;
|
||||
|
||||
params.filterInfo.y = numTaps;
|
||||
params.filterTaps[0].x = 0.0f;
|
||||
params.filterTaps[0].y = 1.0f;
|
||||
|
||||
for (i = 0; i < numHalfTaps; i++) {
|
||||
offset = i + 1;
|
||||
weight = (float)exp(-offset*offset * inverseTwoSigmaSquared);
|
||||
params.filterTaps[i + 1].x = offset;
|
||||
params.filterTaps[i + 1].y = weight;
|
||||
params.filterTaps[i + 1 + numHalfTaps].x = -offset;
|
||||
params.filterTaps[i + 1 + numHalfTaps].y = weight;
|
||||
totalWeight += 2 * weight;
|
||||
}
|
||||
|
||||
// Tap weights will be normalized in shader because side cases on edges of screen
|
||||
// won't have the same number of taps as in the center.
|
||||
}
|
||||
|
||||
void BlurParams::setOutputAlpha(float value) {
|
||||
value = glm::clamp(value, 0.0f, 1.0f);
|
||||
auto filterInfo = _parametersBuffer.get<Params>().filterInfo;
|
||||
if (value != filterInfo.z) {
|
||||
_parametersBuffer.edit<Params>().filterInfo.z = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,17 +136,23 @@ void BlurParams::setLinearDepthPosFar(float farPosDepth) {
|
|||
}
|
||||
|
||||
|
||||
BlurInOutResource::BlurInOutResource(bool generateOutputFramebuffer) :
|
||||
_generateOutputFramebuffer(generateOutputFramebuffer)
|
||||
{
|
||||
|
||||
BlurInOutResource::BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor) :
|
||||
_downsampleFactor(downsampleFactor),
|
||||
_generateOutputFramebuffer(generateOutputFramebuffer) {
|
||||
assert(downsampleFactor > 0);
|
||||
}
|
||||
|
||||
bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFramebuffer, Resources& blurringResources) {
|
||||
if (!sourceFramebuffer) {
|
||||
return false;
|
||||
}
|
||||
if (_blurredFramebuffer && _blurredFramebuffer->getSize() != sourceFramebuffer->getSize()) {
|
||||
|
||||
auto blurBufferSize = sourceFramebuffer->getSize();
|
||||
|
||||
blurBufferSize.x /= _downsampleFactor;
|
||||
blurBufferSize.y /= _downsampleFactor;
|
||||
|
||||
if (_blurredFramebuffer && _blurredFramebuffer->getSize() != blurBufferSize) {
|
||||
_blurredFramebuffer.reset();
|
||||
}
|
||||
|
||||
|
@ -108,7 +164,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
// _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
|
||||
//}
|
||||
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
||||
auto blurringTarget = gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler);
|
||||
auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), blurBufferSize.x, blurBufferSize.y, gpu::Texture::SINGLE_MIP, blurringSampler);
|
||||
_blurredFramebuffer->setRenderBuffer(0, blurringTarget);
|
||||
}
|
||||
|
||||
|
@ -117,7 +173,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
blurringResources.blurringTexture = _blurredFramebuffer->getRenderBuffer(0);
|
||||
|
||||
if (_generateOutputFramebuffer) {
|
||||
if (_outputFramebuffer && _outputFramebuffer->getSize() != sourceFramebuffer->getSize()) {
|
||||
if (_outputFramebuffer && _outputFramebuffer->getSize() != blurBufferSize) {
|
||||
_outputFramebuffer.reset();
|
||||
}
|
||||
|
||||
|
@ -131,7 +187,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
_outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat());
|
||||
}*/
|
||||
auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
||||
auto blurringTarget = gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler);
|
||||
auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), blurBufferSize.x, blurBufferSize.y, gpu::Texture::SINGLE_MIP, blurringSampler);
|
||||
_outputFramebuffer->setRenderBuffer(0, blurringTarget);
|
||||
}
|
||||
|
||||
|
@ -145,8 +201,8 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
return true;
|
||||
}
|
||||
|
||||
BlurGaussian::BlurGaussian(bool generateOutputFramebuffer) :
|
||||
_inOutResources(generateOutputFramebuffer)
|
||||
BlurGaussian::BlurGaussian(bool generateOutputFramebuffer, unsigned int downsampleFactor) :
|
||||
_inOutResources(generateOutputFramebuffer, downsampleFactor)
|
||||
{
|
||||
_parameters = std::make_shared<BlurParams>();
|
||||
}
|
||||
|
@ -196,7 +252,16 @@ gpu::PipelinePointer BlurGaussian::getBlurHPipeline() {
|
|||
}
|
||||
|
||||
void BlurGaussian::configure(const Config& config) {
|
||||
auto state = getBlurHPipeline()->getState();
|
||||
|
||||
_parameters->setFilterRadiusScale(config.filterScale);
|
||||
_parameters->setOutputAlpha(config.mix);
|
||||
if (config.mix < 1.0f) {
|
||||
state->setBlendFunction(config.mix < 1.0f, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
} else {
|
||||
state->setBlendFunction(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -206,7 +271,6 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra
|
|||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
|
||||
BlurInOutResource::Resources blurringResources;
|
||||
if (!_inOutResources.updateResources(sourceFramebuffer, blurringResources)) {
|
||||
// early exit if no valid blurring resources
|
||||
|
@ -216,14 +280,15 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra
|
|||
|
||||
auto blurVPipeline = getBlurVPipeline();
|
||||
auto blurHPipeline = getBlurHPipeline();
|
||||
glm::ivec4 viewport { 0, 0, blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight() };
|
||||
|
||||
_parameters->setWidthHeight(args->_viewport.z, args->_viewport.w, args->isStereo());
|
||||
glm::ivec2 textureSize(blurringResources.sourceTexture->getDimensions());
|
||||
_parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, args->_viewport));
|
||||
glm::ivec2 textureSize = blurredFramebuffer->getSize();
|
||||
_parameters->setWidthHeight(blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight(), args->isStereo());
|
||||
_parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, viewport));
|
||||
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setViewportTransform(viewport);
|
||||
|
||||
batch.setUniformBuffer(BlurTask_ParamsSlot, _parameters->_parametersBuffer);
|
||||
|
||||
|
@ -251,7 +316,7 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra
|
|||
|
||||
|
||||
BlurGaussianDepthAware::BlurGaussianDepthAware(bool generateOutputFramebuffer, const BlurParamsPointer& params) :
|
||||
_inOutResources(generateOutputFramebuffer),
|
||||
_inOutResources(generateOutputFramebuffer, 1U),
|
||||
_parameters((params ? params : std::make_shared<BlurParams>()))
|
||||
{
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "Engine.h"
|
||||
|
||||
#include "BlurTask_shared.slh"
|
||||
|
||||
namespace render {
|
||||
|
||||
|
||||
|
@ -25,6 +27,11 @@ public:
|
|||
void setTexcoordTransform(const glm::vec4 texcoordTransformViewport);
|
||||
|
||||
void setFilterRadiusScale(float scale);
|
||||
void setFilterNumTaps(int count);
|
||||
// Tap 0 is considered the center of the kernel
|
||||
void setFilterTap(int index, float offset, float value);
|
||||
void setFilterGaussianTaps(int numHalfTaps, float sigma = 1.47f);
|
||||
void setOutputAlpha(float value);
|
||||
|
||||
void setDepthPerspective(float oneOverTan2FOV);
|
||||
void setDepthThreshold(float threshold);
|
||||
|
@ -40,7 +47,7 @@ public:
|
|||
// Viewport to Texcoord info, if the region of the blur (viewport) is smaller than the full frame
|
||||
glm::vec4 texcoordTransform{ 0.0f, 0.0f, 1.0f, 1.0f };
|
||||
|
||||
// Filter info (radius scale
|
||||
// Filter info (radius scale, number of taps, output alpha)
|
||||
glm::vec4 filterInfo{ 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
// Depth info (radius scale
|
||||
|
@ -52,6 +59,9 @@ public:
|
|||
// LinearDepth info is { f }
|
||||
glm::vec4 linearDepthInfo{ 0.0f };
|
||||
|
||||
// Taps (offset, weight)
|
||||
glm::vec2 filterTaps[BLUR_MAX_NUM_TAPS];
|
||||
|
||||
Params() {}
|
||||
};
|
||||
gpu::BufferView _parametersBuffer;
|
||||
|
@ -62,7 +72,7 @@ using BlurParamsPointer = std::shared_ptr<BlurParams>;
|
|||
|
||||
class BlurInOutResource {
|
||||
public:
|
||||
BlurInOutResource(bool generateOutputFramebuffer = false);
|
||||
BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor);
|
||||
|
||||
struct Resources {
|
||||
gpu::TexturePointer sourceTexture;
|
||||
|
@ -75,8 +85,9 @@ public:
|
|||
|
||||
gpu::FramebufferPointer _blurredFramebuffer;
|
||||
|
||||
// the output framebuffer defined if the job needs to output the result in a new framebuffer and not in place in th einput buffer
|
||||
// the output framebuffer defined if the job needs to output the result in a new framebuffer and not in place in the input buffer
|
||||
gpu::FramebufferPointer _outputFramebuffer;
|
||||
unsigned int _downsampleFactor{ 1U };
|
||||
bool _generateOutputFramebuffer{ false };
|
||||
};
|
||||
|
||||
|
@ -84,12 +95,15 @@ public:
|
|||
class BlurGaussianConfig : public Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled WRITE setEnabled READ isEnabled NOTIFY dirty) // expose enabled flag
|
||||
Q_PROPERTY(float filterScale MEMBER filterScale NOTIFY dirty) // expose enabled flag
|
||||
Q_PROPERTY(float filterScale MEMBER filterScale NOTIFY dirty)
|
||||
Q_PROPERTY(float mix MEMBER mix NOTIFY dirty)
|
||||
public:
|
||||
|
||||
BlurGaussianConfig() : Job::Config(true) {}
|
||||
|
||||
float filterScale{ 0.2f };
|
||||
float mix{ 1.0f };
|
||||
|
||||
signals :
|
||||
void dirty();
|
||||
|
||||
|
@ -102,11 +116,13 @@ public:
|
|||
using Config = BlurGaussianConfig;
|
||||
using JobModel = Job::ModelIO<BlurGaussian, gpu::FramebufferPointer, gpu::FramebufferPointer, Config>;
|
||||
|
||||
BlurGaussian(bool generateOutputFramebuffer = false);
|
||||
BlurGaussian(bool generateOutputFramebuffer = false, unsigned int downsampleFactor = 1U);
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer);
|
||||
|
||||
BlurParamsPointer getParameters() const { return _parameters; }
|
||||
|
||||
protected:
|
||||
|
||||
BlurParamsPointer _parameters;
|
||||
|
|
|
@ -9,17 +9,7 @@
|
|||
|
||||
<@func declareBlurUniforms()@>
|
||||
|
||||
#define NUM_TAPS 7
|
||||
#define NUM_TAPS_OFFSET 3.0f
|
||||
|
||||
float uniformFilterWidth = 0.05f;
|
||||
|
||||
const float gaussianDistributionCurve[NUM_TAPS] = float[](
|
||||
0.383f, 0.006f, 0.061f, 0.242f, 0.242f, 0.061f, 0.006f
|
||||
);
|
||||
const float gaussianDistributionOffset[NUM_TAPS] = float[](
|
||||
0.0f, -3.0f, -2.0f, -1.0f, 1.0f, 2.0f, 3.0f
|
||||
);
|
||||
<@include BlurTask_shared.slh@>
|
||||
|
||||
struct BlurParameters {
|
||||
vec4 resolutionInfo;
|
||||
|
@ -28,6 +18,7 @@ struct BlurParameters {
|
|||
vec4 depthInfo;
|
||||
vec4 stereoInfo;
|
||||
vec4 linearDepthInfo;
|
||||
vec2 taps[BLUR_MAX_NUM_TAPS];
|
||||
};
|
||||
|
||||
uniform blurParamsBuffer {
|
||||
|
@ -46,6 +37,25 @@ float getFilterScale() {
|
|||
return parameters.filterInfo.x;
|
||||
}
|
||||
|
||||
int getFilterNumTaps() {
|
||||
return int(parameters.filterInfo.y);
|
||||
}
|
||||
|
||||
float getOutputAlpha() {
|
||||
return parameters.filterInfo.z;
|
||||
}
|
||||
|
||||
vec2 getFilterTap(int index) {
|
||||
return parameters.taps[index];
|
||||
}
|
||||
|
||||
float getFilterTapOffset(vec2 tap) {
|
||||
return tap.x;
|
||||
}
|
||||
|
||||
float getFilterTapWeight(vec2 tap) {
|
||||
return tap.y;
|
||||
}
|
||||
|
||||
float getDepthThreshold() {
|
||||
return parameters.depthInfo.x;
|
||||
|
@ -70,19 +80,29 @@ uniform sampler2D sourceMap;
|
|||
|
||||
vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) {
|
||||
texcoord = evalTexcoordTransformed(texcoord);
|
||||
vec4 sampleCenter = texture(sourceMap, texcoord);
|
||||
|
||||
vec2 finalStep = getFilterScale() * direction * pixelStep;
|
||||
vec4 srcBlurred = vec4(0.0);
|
||||
float totalWeight = 0.f;
|
||||
int numTaps = getFilterNumTaps();
|
||||
|
||||
for(int i = 0; i < NUM_TAPS; i++) {
|
||||
// Fetch color and depth for current sample.
|
||||
vec2 sampleCoord = texcoord + (gaussianDistributionOffset[i] * finalStep);
|
||||
vec4 srcSample = texture(sourceMap, sampleCoord);
|
||||
// Accumulate.
|
||||
srcBlurred += gaussianDistributionCurve[i] * srcSample;
|
||||
for(int i = 0; i < numTaps; i++) {
|
||||
vec2 tapInfo = getFilterTap(i);
|
||||
// Fetch color for current sample.
|
||||
vec2 sampleCoord = texcoord + (getFilterTapOffset(tapInfo) * finalStep);
|
||||
if (all(greaterThanEqual(sampleCoord, vec2(0,0))) && all(lessThanEqual(sampleCoord, vec2(1.0,1.0)))) {
|
||||
vec4 srcSample = texture(sourceMap, sampleCoord);
|
||||
float weight = getFilterTapWeight(tapInfo);
|
||||
// Accumulate.
|
||||
srcBlurred += srcSample * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWeight>0.0) {
|
||||
srcBlurred /= totalWeight;
|
||||
}
|
||||
srcBlurred.a = getOutputAlpha();
|
||||
return srcBlurred;
|
||||
}
|
||||
|
||||
|
@ -95,15 +115,6 @@ vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) {
|
|||
uniform sampler2D sourceMap;
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
#define NUM_HALF_TAPS 4
|
||||
|
||||
const float gaussianDistributionCurveHalf[NUM_HALF_TAPS] = float[](
|
||||
0.383f, 0.242f, 0.061f, 0.006f
|
||||
);
|
||||
const float gaussianDistributionOffsetHalf[NUM_HALF_TAPS] = float[](
|
||||
0.0f, 1.0f, 2.0f, 3.0f
|
||||
);
|
||||
|
||||
vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep) {
|
||||
texcoord = evalTexcoordTransformed(texcoord);
|
||||
float sampleDepth = texture(depthMap, texcoord).x;
|
||||
|
@ -122,45 +133,36 @@ vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep
|
|||
float scale = distanceToProjectionWindow / sampleDepth;
|
||||
|
||||
vec2 finalStep = filterScale * scale * direction * pixelStep;
|
||||
int numTaps = getFilterNumTaps();
|
||||
|
||||
// Accumulate the center sample
|
||||
vec4 srcBlurred = gaussianDistributionCurve[0] * sampleCenter;
|
||||
vec2 tapInfo = getFilterTap(0);
|
||||
float totalWeight = getFilterTapWeight(tapInfo);
|
||||
vec4 srcBlurred = sampleCenter * totalWeight;
|
||||
|
||||
for(int i = 1; i < numTaps; i++) {
|
||||
tapInfo = getFilterTap(i);
|
||||
|
||||
for(int i = 1; i < NUM_TAPS; i++) {
|
||||
// Fetch color and depth for current sample.
|
||||
vec2 sampleCoord = texcoord + (gaussianDistributionOffset[i] * finalStep);
|
||||
float srcDepth = texture(depthMap, sampleCoord).x;
|
||||
vec4 srcSample = texture(sourceMap, sampleCoord);
|
||||
vec2 sampleCoord = texcoord + (getFilterTapOffset(tapInfo) * finalStep);
|
||||
if (all(greaterThanEqual(sampleCoord, vec2(0,0))) && all(lessThanEqual(sampleCoord, vec2(1.0,1.0)))) {
|
||||
float srcDepth = texture(depthMap, sampleCoord).x;
|
||||
vec4 srcSample = texture(sourceMap, sampleCoord);
|
||||
float weight = getFilterTapWeight(tapInfo);
|
||||
|
||||
// If the difference in depth is huge, we lerp color back.
|
||||
float s = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepth - sampleDepth), 0.0, 1.0);
|
||||
srcSample = mix(srcSample, sampleCenter, s);
|
||||
// If the difference in depth is huge, we lerp color back.
|
||||
float s = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepth - sampleDepth), 0.0, 1.0);
|
||||
srcSample = mix(srcSample, sampleCenter, s);
|
||||
|
||||
// Accumulate.
|
||||
srcBlurred += gaussianDistributionCurve[i] * srcSample;
|
||||
// Accumulate.
|
||||
srcBlurred += srcSample * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for(int i = 1; i < NUM_HALF_TAPS; i++) {
|
||||
// Fetch color and depth for current sample.
|
||||
vec2 texcoordOffset = (gaussianDistributionOffsetHalf[i] * finalStep);
|
||||
|
||||
float srcDepthN = texture(depthMap, texcoord - texcoordOffset).x;
|
||||
float srcDepthP = texture(depthMap, texcoord + texcoordOffset).x;
|
||||
vec4 srcSampleN = texture(sourceMap, texcoord - texcoordOffset);
|
||||
vec4 srcSampleP = texture(sourceMap, texcoord + texcoordOffset);
|
||||
|
||||
// If the difference in depth is huge, we lerp color back.
|
||||
float sN = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepthN - sampleDepth), 0.0, 1.0);
|
||||
float sP = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepthP - sampleDepth), 0.0, 1.0);
|
||||
|
||||
srcSampleN = mix(srcSampleN, sampleCenter, sN);
|
||||
srcSampleP = mix(srcSampleP, sampleCenter, sP);
|
||||
|
||||
// Accumulate.
|
||||
srcBlurred += gaussianDistributionCurveHalf[i] * (srcSampleP + srcSampleN);
|
||||
}*/
|
||||
|
||||
if (totalWeight>0.0) {
|
||||
srcBlurred /= totalWeight;
|
||||
}
|
||||
return srcBlurred;
|
||||
}
|
||||
|
||||
|
|
10
libraries/render/src/render/BlurTask_shared.slh
Normal file
10
libraries/render/src/render/BlurTask_shared.slh
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Created by Olivier Prat on 09/25/17.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
#define BLUR_MAX_NUM_TAPS 33
|
|
@ -20,7 +20,7 @@
|
|||
#include <PerfStat.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <drawItemBounds_vert.h>
|
||||
#include <drawItemBounds_frag.h>
|
||||
|
@ -215,3 +215,85 @@ void DrawBounds::run(const RenderContextPointer& renderContext,
|
|||
});
|
||||
}
|
||||
|
||||
gpu::PipelinePointer DrawFrustum::_pipeline;
|
||||
gpu::BufferView DrawFrustum::_frustumMeshIndices;
|
||||
|
||||
DrawFrustum::DrawFrustum(const glm::vec3& color) :
|
||||
_color{ color } {
|
||||
_frustumMeshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
|
||||
_frustumMeshStream.addBuffer(_frustumMeshVertices._buffer, _frustumMeshVertices._offset, _frustumMeshVertices._stride);
|
||||
}
|
||||
|
||||
void DrawFrustum::configure(const Config& configuration) {
|
||||
_updateFrustum = !configuration.isFrozen;
|
||||
}
|
||||
|
||||
void DrawFrustum::run(const render::RenderContextPointer& renderContext, const Input& input) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_context);
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
if (input) {
|
||||
const auto& frustum = *input;
|
||||
|
||||
static uint8_t indexData[] = { 0, 1, 2, 3, 0, 4, 5, 6, 7, 4, 5, 1, 2, 6, 7, 3 };
|
||||
|
||||
if (!_frustumMeshIndices._buffer) {
|
||||
auto indices = std::make_shared<gpu::Buffer>(sizeof(indexData), indexData);
|
||||
_frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX));
|
||||
}
|
||||
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawColorPS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("color", 0));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(true, false));
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
if (_updateFrustum) {
|
||||
updateFrustum(frustum);
|
||||
}
|
||||
|
||||
// Render the frustums in wireframe
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||
args->getViewFrustum().evalViewTransform(viewMat);
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
batch.setPipeline(_pipeline);
|
||||
batch.setIndexBuffer(_frustumMeshIndices);
|
||||
|
||||
batch._glUniform4f(0, _color.x, _color.y, _color.z, 1.0f);
|
||||
batch.setInputStream(0, _frustumMeshStream);
|
||||
batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U);
|
||||
|
||||
args->_batch = nullptr;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DrawFrustum::updateFrustum(const ViewFrustum& frustum) {
|
||||
auto& vertices = _frustumMeshVertices.edit<std::array<glm::vec3, 8U> >();
|
||||
vertices[0] = frustum.getNearTopLeft();
|
||||
vertices[1] = frustum.getNearTopRight();
|
||||
vertices[2] = frustum.getNearBottomRight();
|
||||
vertices[3] = frustum.getNearBottomLeft();
|
||||
vertices[4] = frustum.getFarTopLeft();
|
||||
vertices[5] = frustum.getFarTopRight();
|
||||
vertices[6] = frustum.getFarBottomRight();
|
||||
vertices[7] = frustum.getFarBottomLeft();
|
||||
}
|
||||
|
|
|
@ -70,6 +70,43 @@ private:
|
|||
int _colorLocation { -1 };
|
||||
};
|
||||
|
||||
class DrawFrustumConfig : public render::JobConfig {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isFrozen MEMBER isFrozen NOTIFY dirty)
|
||||
public:
|
||||
|
||||
DrawFrustumConfig(bool enabled = false) : JobConfig(enabled) {}
|
||||
|
||||
bool isFrozen{ false };
|
||||
signals:
|
||||
void dirty();
|
||||
|
||||
};
|
||||
|
||||
class DrawFrustum {
|
||||
public:
|
||||
using Config = DrawFrustumConfig;
|
||||
using Input = ViewFrustumPointer;
|
||||
using JobModel = render::Job::ModelI<DrawFrustum, Input, Config>;
|
||||
|
||||
DrawFrustum(const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
void configure(const Config& configuration);
|
||||
void run(const render::RenderContextPointer& renderContext, const Input& input);
|
||||
|
||||
private:
|
||||
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
static gpu::BufferView _frustumMeshIndices;
|
||||
|
||||
bool _updateFrustum{ true };
|
||||
gpu::BufferView _frustumMeshVertices;
|
||||
gpu::BufferStream _frustumMeshStream;
|
||||
glm::vec3 _color;
|
||||
|
||||
void updateFrustum(const ViewFrustum& frustum);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_render_DrawTask_h
|
||||
|
|
83
libraries/render/src/render/ResampleTask.cpp
Normal file
83
libraries/render/src/render/ResampleTask.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// ResampleTask.cpp
|
||||
// render/src/render
|
||||
//
|
||||
// Various to upsample or downsample textures into framebuffers.
|
||||
//
|
||||
// Created by Olivier Prat on 10/09/17.
|
||||
// Copyright 2017 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 "ResampleTask.h"
|
||||
|
||||
#include "gpu/Context.h"
|
||||
#include "gpu/StandardShaderLib.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
gpu::PipelinePointer HalfDownsample::_pipeline;
|
||||
|
||||
HalfDownsample::HalfDownsample() {
|
||||
|
||||
}
|
||||
|
||||
void HalfDownsample::configure(const Config& config) {
|
||||
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer HalfDownsample::getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer) {
|
||||
auto resampledFramebufferSize = sourceFramebuffer->getSize();
|
||||
|
||||
resampledFramebufferSize.x /= 2U;
|
||||
resampledFramebufferSize.y /= 2U;
|
||||
|
||||
if (!_destinationFrameBuffer || resampledFramebufferSize != _destinationFrameBuffer->getSize()) {
|
||||
_destinationFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("HalfOutput"));
|
||||
|
||||
auto sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
||||
auto target = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), resampledFramebufferSize.x, resampledFramebufferSize.y, gpu::Texture::SINGLE_MIP, sampler);
|
||||
_destinationFrameBuffer->setRenderBuffer(0, target);
|
||||
}
|
||||
return _destinationFrameBuffer;
|
||||
}
|
||||
|
||||
void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer);
|
||||
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
const auto bufferSize = resampledFrameBuffer->getSize();
|
||||
glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y };
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setFramebuffer(resampledFrameBuffer);
|
||||
|
||||
batch.setViewportTransform(viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport));
|
||||
batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
41
libraries/render/src/render/ResampleTask.h
Normal file
41
libraries/render/src/render/ResampleTask.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// ResampleTask.h
|
||||
// render/src/render
|
||||
//
|
||||
// Various to upsample or downsample textures into framebuffers.
|
||||
//
|
||||
// Created by Olivier Prat on 10/09/17.
|
||||
// Copyright 2017 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_render_ResampleTask_h
|
||||
#define hifi_render_ResampleTask_h
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
class HalfDownsample {
|
||||
public:
|
||||
using Config = JobConfig;
|
||||
using JobModel = Job::ModelIO<HalfDownsample, gpu::FramebufferPointer, gpu::FramebufferPointer, Config>;
|
||||
|
||||
HalfDownsample();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer);
|
||||
|
||||
protected:
|
||||
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
|
||||
gpu::FramebufferPointer _destinationFrameBuffer;
|
||||
|
||||
gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_render_ResampleTask_h
|
|
@ -40,7 +40,8 @@ struct BackToFrontSort {
|
|||
}
|
||||
};
|
||||
|
||||
void render::depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||
void render::depthSortItems(const RenderContextPointer& renderContext, bool frontToBack,
|
||||
const ItemBounds& inItems, ItemBounds& outItems, AABox* bounds) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
|
@ -74,12 +75,26 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron
|
|||
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
|
||||
}
|
||||
|
||||
// Finally once sorted result to a list of itemID
|
||||
// Finally once sorted result to a list of itemID and keep uniques
|
||||
render::ItemID previousID = Item::INVALID_ITEM_ID;
|
||||
for (auto& item : itemBoundSorts) {
|
||||
if (item._id != previousID) {
|
||||
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
||||
previousID = item._id;
|
||||
if (!bounds) {
|
||||
for (auto& item : itemBoundSorts) {
|
||||
if (item._id != previousID) {
|
||||
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
||||
previousID = item._id;
|
||||
}
|
||||
}
|
||||
} else if (!itemBoundSorts.empty()) {
|
||||
if (bounds->isNull()) {
|
||||
*bounds = itemBoundSorts.front()._bounds;
|
||||
}
|
||||
for (auto& item : itemBoundSorts) {
|
||||
if (item._id != previousID) {
|
||||
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
||||
previousID = item._id;
|
||||
*bounds += item._bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +134,27 @@ void DepthSortShapes::run(const RenderContextPointer& renderContext, const Shape
|
|||
}
|
||||
}
|
||||
|
||||
void DepthSortShapesAndComputeBounds::run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, Outputs& outputs) {
|
||||
auto& outShapes = outputs.edit0();
|
||||
auto& outBounds = outputs.edit1();
|
||||
|
||||
outShapes.clear();
|
||||
outShapes.reserve(inShapes.size());
|
||||
outBounds = AABox();
|
||||
|
||||
for (auto& pipeline : inShapes) {
|
||||
auto& inItems = pipeline.second;
|
||||
auto outItems = outShapes.find(pipeline.first);
|
||||
if (outItems == outShapes.end()) {
|
||||
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first;
|
||||
}
|
||||
AABox bounds;
|
||||
|
||||
depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &bounds);
|
||||
outBounds += bounds;
|
||||
}
|
||||
}
|
||||
|
||||
void DepthSortItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
|
||||
depthSortItems(renderContext, _frontToBack, inItems, outItems);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "Engine.h"
|
||||
|
||||
namespace render {
|
||||
void depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems);
|
||||
void depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems, AABox* bounds = nullptr);
|
||||
|
||||
class PipelineSortShapes {
|
||||
public:
|
||||
|
@ -33,6 +33,17 @@ namespace render {
|
|||
void run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes);
|
||||
};
|
||||
|
||||
class DepthSortShapesAndComputeBounds {
|
||||
public:
|
||||
using Outputs = VaryingSet2<ShapeBounds, AABox>;
|
||||
using JobModel = Job::ModelIO<DepthSortShapesAndComputeBounds, ShapeBounds, Outputs>;
|
||||
|
||||
bool _frontToBack;
|
||||
DepthSortShapesAndComputeBounds(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
||||
|
||||
void run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, Outputs& outputs);
|
||||
};
|
||||
|
||||
class DepthSortItems {
|
||||
public:
|
||||
using JobModel = Job::ModelIO<DepthSortItems, ItemBounds, ItemBounds>;
|
||||
|
|
|
@ -171,6 +171,8 @@ public:
|
|||
_concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0);
|
||||
}
|
||||
|
||||
const std::string& getName() const { return _name; }
|
||||
|
||||
protected:
|
||||
ConceptPointer _concept;
|
||||
std::string _name = "";
|
||||
|
@ -206,6 +208,24 @@ public:
|
|||
|
||||
const Varying getInput() const override { return _input; }
|
||||
const Varying getOutput() const override { return _output; }
|
||||
typename Jobs::iterator editJob(std::string name) {
|
||||
typename Jobs::iterator jobIt;
|
||||
for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) {
|
||||
if (jobIt->getName() == name) {
|
||||
return jobIt;
|
||||
}
|
||||
}
|
||||
return jobIt;
|
||||
}
|
||||
typename Jobs::const_iterator getJob(std::string name) const {
|
||||
typename Jobs::const_iterator jobIt;
|
||||
for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) {
|
||||
if (jobIt->getName() == name) {
|
||||
return jobIt;
|
||||
}
|
||||
}
|
||||
return jobIt;
|
||||
}
|
||||
|
||||
TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {}
|
||||
|
||||
|
|
|
@ -127,10 +127,11 @@ public:
|
|||
|
||||
AABox getOctreeChild(OctreeChild child) const; // returns the AABox of the would be octree child of this AABox
|
||||
|
||||
glm::vec4 getPlane(BoxFace face) const;
|
||||
|
||||
private:
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
|
||||
glm::vec4 getPlane(BoxFace face) const;
|
||||
|
||||
static BoxFace getOppositeFace(BoxFace face);
|
||||
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <bitset>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "GLMHelpers.h"
|
||||
#include "Plane.h"
|
||||
|
||||
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) {
|
||||
// compute the projection of the point vector onto the segment vector
|
||||
|
@ -314,6 +316,134 @@ bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
return false;
|
||||
}
|
||||
|
||||
static void getTrianglePlaneIntersectionPoints(const glm::vec3 trianglePoints[3], const float pointPlaneDistances[3],
|
||||
const int clippedPointIndex, const int keptPointIndices[2],
|
||||
glm::vec3 points[2]) {
|
||||
assert(clippedPointIndex >= 0 && clippedPointIndex < 3);
|
||||
const auto& clippedPoint = trianglePoints[clippedPointIndex];
|
||||
const float clippedPointPlaneDistance = pointPlaneDistances[clippedPointIndex];
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
assert(keptPointIndices[i] >= 0 && keptPointIndices[i] < 3);
|
||||
const auto& keptPoint = trianglePoints[keptPointIndices[i]];
|
||||
const float keptPointPlaneDistance = pointPlaneDistances[keptPointIndices[i]];
|
||||
auto intersectionEdgeRatio = clippedPointPlaneDistance / (clippedPointPlaneDistance - keptPointPlaneDistance);
|
||||
points[i] = clippedPoint + (keptPoint - clippedPoint) * intersectionEdgeRatio;
|
||||
}
|
||||
}
|
||||
|
||||
int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount) {
|
||||
float pointDistanceToPlane[3];
|
||||
std::bitset<3> arePointsClipped;
|
||||
glm::vec3 triangleVertices[3] = { triangle.v0, triangle.v1, triangle.v2 };
|
||||
int clippedTriangleCount = 0;
|
||||
int i;
|
||||
|
||||
assert(clippedTriangleCount > 0);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
pointDistanceToPlane[i] = plane.distance(triangleVertices[i]);
|
||||
arePointsClipped.set(i, pointDistanceToPlane[i] < 0.0f);
|
||||
}
|
||||
|
||||
switch (arePointsClipped.count()) {
|
||||
case 0:
|
||||
// Easy, the entire triangle is kept as is.
|
||||
*clippedTriangles = triangle;
|
||||
clippedTriangleCount = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
int clippedPointIndex = 2;
|
||||
int keptPointIndices[2] = { 0, 1 };
|
||||
glm::vec3 newVertices[2];
|
||||
|
||||
// Determine which point was clipped.
|
||||
if (arePointsClipped.test(0)) {
|
||||
clippedPointIndex = 0;
|
||||
keptPointIndices[0] = 2;
|
||||
} else if (arePointsClipped.test(1)) {
|
||||
clippedPointIndex = 1;
|
||||
keptPointIndices[1] = 2;
|
||||
}
|
||||
// We have a quad now, so we need to create two triangles.
|
||||
getTrianglePlaneIntersectionPoints(triangleVertices, pointDistanceToPlane, clippedPointIndex, keptPointIndices, newVertices);
|
||||
clippedTriangles->v0 = triangleVertices[keptPointIndices[0]];
|
||||
clippedTriangles->v1 = triangleVertices[keptPointIndices[1]];
|
||||
clippedTriangles->v2 = newVertices[1];
|
||||
clippedTriangles++;
|
||||
clippedTriangleCount++;
|
||||
|
||||
if (clippedTriangleCount < maxClippedTriangleCount) {
|
||||
clippedTriangles->v0 = triangleVertices[keptPointIndices[0]];
|
||||
clippedTriangles->v1 = newVertices[0];
|
||||
clippedTriangles->v2 = newVertices[1];
|
||||
clippedTriangles++;
|
||||
clippedTriangleCount++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
int keptPointIndex = 2;
|
||||
int clippedPointIndices[2] = { 0, 1 };
|
||||
glm::vec3 newVertices[2];
|
||||
|
||||
// Determine which point was NOT clipped.
|
||||
if (!arePointsClipped.test(0)) {
|
||||
keptPointIndex = 0;
|
||||
clippedPointIndices[0] = 2;
|
||||
} else if (!arePointsClipped.test(1)) {
|
||||
keptPointIndex = 1;
|
||||
clippedPointIndices[1] = 2;
|
||||
}
|
||||
// We have a single triangle
|
||||
getTrianglePlaneIntersectionPoints(triangleVertices, pointDistanceToPlane, keptPointIndex, clippedPointIndices, newVertices);
|
||||
clippedTriangles->v0 = triangleVertices[keptPointIndex];
|
||||
clippedTriangles->v1 = newVertices[0];
|
||||
clippedTriangles->v2 = newVertices[1];
|
||||
clippedTriangleCount = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Entire triangle is clipped.
|
||||
break;
|
||||
}
|
||||
|
||||
return clippedTriangleCount;
|
||||
}
|
||||
|
||||
int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount) {
|
||||
auto planesEnd = planes + planeCount;
|
||||
int triangleCount = 1;
|
||||
std::vector<Triangle> trianglesToTest;
|
||||
|
||||
assert(maxClippedTriangleCount > 0);
|
||||
|
||||
*clippedTriangles = triangle;
|
||||
|
||||
while (planes < planesEnd) {
|
||||
int clippedSubTriangleCount;
|
||||
|
||||
trianglesToTest.clear();
|
||||
trianglesToTest.insert(trianglesToTest.begin(), clippedTriangles, clippedTriangles + triangleCount);
|
||||
triangleCount = 0;
|
||||
|
||||
for (const auto& triangleToTest : trianglesToTest) {
|
||||
clippedSubTriangleCount = clipTriangleWithPlane(triangleToTest, *planes,
|
||||
clippedTriangles + triangleCount, maxClippedTriangleCount - triangleCount);
|
||||
triangleCount += clippedSubTriangleCount;
|
||||
if (triangleCount >= maxClippedTriangleCount) {
|
||||
return triangleCount;
|
||||
}
|
||||
}
|
||||
++planes;
|
||||
}
|
||||
return triangleCount;
|
||||
}
|
||||
|
||||
// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect?
|
||||
// from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html
|
||||
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) {
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
|
||||
class Plane;
|
||||
|
||||
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end);
|
||||
|
||||
/// Computes the penetration between a point and a sphere (centered at the origin)
|
||||
|
@ -109,6 +111,8 @@ inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3
|
|||
return findRayTriangleIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance, allowBackface);
|
||||
}
|
||||
|
||||
int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount);
|
||||
int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount);
|
||||
|
||||
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2);
|
||||
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
class Plane {
|
||||
public:
|
||||
Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1,v2,v3); }
|
||||
Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1, v2, v3); }
|
||||
Plane(const glm::vec3 &normal, const glm::vec3 &point) { setNormalAndPoint(normal, point); }
|
||||
Plane(float a, float b, float c, float d) { setCoefficients(a, b, c, d); }
|
||||
Plane() : _normal(0.0f), _point(0.0f), _dCoefficient(0.0f) {};
|
||||
~Plane() {} ;
|
||||
|
||||
|
|
|
@ -1081,7 +1081,7 @@ void setMaxCores(uint8_t maxCores) {
|
|||
void quitWithParentProcess() {
|
||||
if (qApp) {
|
||||
qDebug() << "Parent process died, quitting";
|
||||
qApp->quit();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1113,3 +1113,57 @@ void watchParentProcess(int parentPID) {
|
|||
timer->start();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString getLastErrorAsString() {
|
||||
DWORD errorMessageID = ::GetLastError();
|
||||
if (errorMessageID == 0) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
LPSTR messageBuffer = nullptr;
|
||||
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, nullptr);
|
||||
|
||||
auto message = QString::fromLocal8Bit(messageBuffer, (int)size);
|
||||
|
||||
//Free the buffer.
|
||||
LocalFree(messageBuffer);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
// All processes in the group will shut down with the process creating the group
|
||||
void* createProcessGroup() {
|
||||
HANDLE jobObject = CreateJobObject(nullptr, nullptr);
|
||||
if (jobObject == nullptr) {
|
||||
qWarning() << "Could NOT create job object:" << getLastErrorAsString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION JELI;
|
||||
if (!QueryInformationJobObject(jobObject, JobObjectExtendedLimitInformation, &JELI, sizeof(JELI), nullptr)) {
|
||||
qWarning() << "Could NOT query job object information" << getLastErrorAsString();
|
||||
return nullptr;
|
||||
}
|
||||
JELI.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
if (!SetInformationJobObject(jobObject, JobObjectExtendedLimitInformation, &JELI, sizeof(JELI))) {
|
||||
qWarning() << "Could NOT set job object information" << getLastErrorAsString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return jobObject;
|
||||
}
|
||||
|
||||
void addProcessToGroup(void* processGroup, qint64 processId) {
|
||||
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
|
||||
if (hProcess == nullptr) {
|
||||
qCritical() << "Could NOT open process" << getLastErrorAsString();
|
||||
}
|
||||
if (!AssignProcessToJobObject(processGroup, hProcess)) {
|
||||
qCritical() << "Could NOT assign process to job object" << getLastErrorAsString();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -238,4 +238,10 @@ void setMaxCores(uint8_t maxCores);
|
|||
const QString PARENT_PID_OPTION = "parent-pid";
|
||||
void watchParentProcess(int parentPID);
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void* createProcessGroup();
|
||||
void addProcessToGroup(void* processGroup, qint64 processId);
|
||||
#endif
|
||||
|
||||
#endif // hifi_SharedUtil_h
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
|
||||
Vec4 transform(const Vec4& pos) const;
|
||||
Vec3 transform(const Vec3& pos) const;
|
||||
Vec3 transformDirection(const Vec3& dir) const;
|
||||
|
||||
bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); }
|
||||
|
||||
|
@ -541,6 +542,13 @@ inline Transform::Vec3 Transform::transform(const Vec3& pos) const {
|
|||
return Vec3(result.x / result.w, result.y / result.w, result.z / result.w);
|
||||
}
|
||||
|
||||
inline Transform::Vec3 Transform::transformDirection(const Vec3& dir) const {
|
||||
Mat4 m;
|
||||
getMatrix(m);
|
||||
Vec4 result = m * Vec4(dir, 0.0f);
|
||||
return Vec3(result.x, result.y, result.z);
|
||||
}
|
||||
|
||||
inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result) const {
|
||||
updateCache();
|
||||
result = (*_matrix);
|
||||
|
|
|
@ -96,7 +96,6 @@ function rayCastTest() {
|
|||
color: color,
|
||||
alpha: 1,
|
||||
visible: visible,
|
||||
lineWidth: 2,
|
||||
start: origin,
|
||||
end: Vec3.sum(origin,Vec3.multiply(5,direction))
|
||||
});
|
||||
|
|
119
scripts/developer/utilities/render/bloom.qml
Normal file
119
scripts/developer/utilities/render/bloom.qml
Normal file
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// bloom.qml
|
||||
// developer/utilities/render
|
||||
//
|
||||
// Olivier Prat, created on 09/25/2017.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "configSlider"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var config: Render.getConfig("RenderMainView.Bloom")
|
||||
property var configThreshold: Render.getConfig("RenderMainView.BloomThreshold")
|
||||
property var configDebug: Render.getConfig("RenderMainView.DebugBloom")
|
||||
|
||||
Column {
|
||||
spacing: 8
|
||||
|
||||
CheckBox {
|
||||
text: "Enable"
|
||||
checked: root.config["enabled"]
|
||||
onCheckedChanged: {
|
||||
root.config["enabled"] = checked;
|
||||
}
|
||||
}
|
||||
GroupBox {
|
||||
title: "Debug"
|
||||
Row {
|
||||
ExclusiveGroup { id: debugGroup }
|
||||
RadioButton {
|
||||
text : "Off"
|
||||
checked : !root.configDebug["enabled"]
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
root.configDebug["enabled"] = false
|
||||
}
|
||||
}
|
||||
exclusiveGroup : debugGroup
|
||||
}
|
||||
RadioButton {
|
||||
text : "Lvl 0"
|
||||
checked :root.configDebug["enabled"] && root.configDebug["mode"]==0
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
root.configDebug["enabled"] = true
|
||||
root.configDebug["mode"] = 0
|
||||
}
|
||||
}
|
||||
exclusiveGroup : debugGroup
|
||||
}
|
||||
RadioButton {
|
||||
text : "Lvl 1"
|
||||
checked : root.configDebug["enabled"] && root.configDebug["mode"]==1
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
root.configDebug["enabled"] = true
|
||||
root.configDebug["mode"] = 1
|
||||
}
|
||||
}
|
||||
exclusiveGroup : debugGroup
|
||||
}
|
||||
RadioButton {
|
||||
text : "Lvl 2"
|
||||
checked : root.configDebug["enabled"] && root.configDebug["mode"]==2
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
root.configDebug["enabled"] = true
|
||||
root.configDebug["mode"] = 2
|
||||
}
|
||||
}
|
||||
exclusiveGroup : debugGroup
|
||||
}
|
||||
RadioButton {
|
||||
text : "All"
|
||||
checked : root.configDebug["enabled"] && root.configDebug["mode"]==3
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
root.configDebug["enabled"] = true
|
||||
root.configDebug["mode"] = 3
|
||||
}
|
||||
}
|
||||
exclusiveGroup : debugGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Intensity"
|
||||
integral: false
|
||||
config: root.config
|
||||
property: "intensity"
|
||||
max: 5.0
|
||||
min: 0.0
|
||||
width: 280
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Size"
|
||||
integral: false
|
||||
config: root.config
|
||||
property: "size"
|
||||
max: 1.0
|
||||
min: 0.0
|
||||
width: 280
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Threshold"
|
||||
integral: false
|
||||
config: root.configThreshold
|
||||
property: "threshold"
|
||||
max: 2.0
|
||||
min: 0.0
|
||||
width: 280
|
||||
}
|
||||
}
|
||||
}
|
20
scripts/developer/utilities/render/debugBloom.js
Normal file
20
scripts/developer/utilities/render/debugBloom.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// debugBloom.js
|
||||
// developer/utilities/render
|
||||
//
|
||||
// Olivier Prat, created on 09/25/2017.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('bloom.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Bloom',
|
||||
source: qml,
|
||||
width: 285,
|
||||
height: 170,
|
||||
});
|
||||
window.closed.connect(function() { Script.stop(); });
|
20
scripts/developer/utilities/render/debugShadow.js
Normal file
20
scripts/developer/utilities/render/debugShadow.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// debugShadow.js
|
||||
// developer/utilities/render
|
||||
//
|
||||
// Olivier Prat, created on 10/25/2017.
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('shadow.qml');
|
||||
var window = new OverlayWindow({
|
||||
title: 'Shadow Debug',
|
||||
source: qml,
|
||||
width: 200,
|
||||
height: 90
|
||||
});
|
||||
window.closed.connect(function() { Script.stop(); });
|
50
scripts/developer/utilities/render/shadow.qml
Normal file
50
scripts/developer/utilities/render/shadow.qml
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// shadow.qml
|
||||
// developer/utilities/render
|
||||
//
|
||||
// Olivier Prat, created on 10/25/2017.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Column {
|
||||
id: root
|
||||
spacing: 8
|
||||
property var viewConfig: Render.getConfig("RenderMainView.DrawViewFrustum");
|
||||
property var shadowConfig: Render.getConfig("RenderMainView.DrawShadowFrustum");
|
||||
|
||||
Component.onCompleted: {
|
||||
viewConfig.enabled = true;
|
||||
shadowConfig.enabled = true;
|
||||
}
|
||||
Component.onDestruction: {
|
||||
viewConfig.enabled = false;
|
||||
shadowConfig.enabled = false;
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
text: "Freeze Frustums"
|
||||
checked: false
|
||||
onCheckedChanged: {
|
||||
viewConfig.isFrozen = checked;
|
||||
shadowConfig.isFrozen = checked;
|
||||
}
|
||||
}
|
||||
Row {
|
||||
spacing: 8
|
||||
Label {
|
||||
text: "View"
|
||||
color: "yellow"
|
||||
font.italic: true
|
||||
}
|
||||
Label {
|
||||
text: "Shadow"
|
||||
color: "blue"
|
||||
font.italic: true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -284,8 +284,7 @@
|
|||
endParentJointIndex: yourJointIndex,
|
||||
end: yourJointPosition,
|
||||
color: identifyAvatarLineColor,
|
||||
alpha: 1,
|
||||
lineWidth: 1
|
||||
alpha: 1
|
||||
};
|
||||
|
||||
avatarIdentifiers[yourAvatarID] = identifierParams;
|
||||
|
|
|
@ -389,7 +389,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Controller.enableMapping(MAPPING_NAME);
|
||||
|
||||
this.leftControllerRayPick = RayPick.createRayPick({
|
||||
joint: "_CONTROLLER_LEFTHAND",
|
||||
joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
enabled: true,
|
||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||
|
@ -403,7 +403,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
|
||||
});
|
||||
this.rightControllerRayPick = RayPick.createRayPick({
|
||||
joint: "_CONTROLLER_RIGHTHAND",
|
||||
joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
enabled: true,
|
||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||
|
|
|
@ -33,7 +33,6 @@ Script.include("/~/system/libraries/Xform.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -55,7 +54,6 @@ Script.include("/~/system/libraries/Xform.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -77,7 +75,6 @@ Script.include("/~/system/libraries/Xform.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -649,6 +646,7 @@ Script.include("/~/system/libraries/Xform.js");
|
|||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
distanceScaleEnd: true,
|
||||
scaleWithAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -47,7 +46,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -69,7 +67,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -190,6 +187,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
distanceScaleEnd: true,
|
||||
scaleWithAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawHUDLayer: true,
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -53,7 +52,6 @@
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawHUDLayer: true,
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -75,7 +73,6 @@
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawHUDLayer: true,
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
|
|
@ -27,7 +27,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -49,7 +48,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -71,7 +69,6 @@ Script.include("/~/system/libraries/utils.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -237,6 +234,7 @@ Script.include("/~/system/libraries/utils.js");
|
|||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -48,7 +47,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -70,7 +68,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -365,12 +362,13 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
this.laserPointer = LaserPointers.createLaserPointer({
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_OVERLAYS,
|
||||
maxDistance: PICK_MAX_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
|
||||
filter: RayPick.PICK_ENTITIES,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
centerEndY: false,
|
||||
renderStates: teleportRenderStates,
|
||||
defaultRenderStates: teleportDefaultRenderStates
|
||||
|
@ -161,6 +162,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
centerEndY: false,
|
||||
renderStates: teleportRenderStates
|
||||
});
|
||||
|
@ -168,6 +170,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: "Avatar",
|
||||
filter: RayPick.PICK_ENTITIES,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
centerEndY: false,
|
||||
renderStates: teleportRenderStates,
|
||||
defaultRenderStates: teleportDefaultRenderStates
|
||||
|
@ -176,6 +179,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: "Avatar",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
centerEndY: false,
|
||||
renderStates: teleportRenderStates
|
||||
});
|
||||
|
|
|
@ -26,7 +26,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -48,7 +47,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -70,7 +68,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
alpha: 1,
|
||||
solid: true,
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
drawInFront: true, // Even when burried inside of something, show it.
|
||||
parentID: MyAvatar.SELF_ID
|
||||
|
@ -88,7 +85,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
{name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath}
|
||||
];
|
||||
|
||||
|
||||
// triggered when stylus presses a web overlay/entity
|
||||
var HAPTIC_STYLUS_STRENGTH = 1.0;
|
||||
var HAPTIC_STYLUS_DURATION = 20.0;
|
||||
|
@ -452,6 +448,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
scaleWithAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
});
|
||||
}
|
||||
|
|
|
@ -318,6 +318,15 @@
|
|||
});
|
||||
}
|
||||
|
||||
function injectUnfocusOnSearch() {
|
||||
// unfocus input field on search, thus hiding virtual keyboard
|
||||
$('#search-box').on('submit', function () {
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function injectHiFiCode() {
|
||||
if (commerceMode) {
|
||||
maybeAddLogInButton();
|
||||
|
@ -347,6 +356,8 @@
|
|||
maybeAddPurchasesButton();
|
||||
}
|
||||
}
|
||||
|
||||
injectUnfocusOnSearch();
|
||||
}
|
||||
|
||||
function injectHiFiItemPageCode() {
|
||||
|
@ -386,6 +397,8 @@
|
|||
maybeAddPurchasesButton();
|
||||
}
|
||||
}
|
||||
|
||||
injectUnfocusOnSearch();
|
||||
}
|
||||
|
||||
function updateClaraCode() {
|
||||
|
|
|
@ -339,7 +339,6 @@ SelectionDisplay = (function() {
|
|||
solid: grabberSolid,
|
||||
visible: false,
|
||||
dashed: false,
|
||||
lineWidth: grabberLineWidth,
|
||||
drawInFront: true,
|
||||
borderSize: 1.4
|
||||
};
|
||||
|
@ -352,7 +351,6 @@ SelectionDisplay = (function() {
|
|||
solid: grabberSolid,
|
||||
visible: false,
|
||||
dashed: false,
|
||||
lineWidth: grabberLineWidth,
|
||||
drawInFront: true,
|
||||
borderSize: 1.4
|
||||
};
|
||||
|
@ -365,7 +363,6 @@ SelectionDisplay = (function() {
|
|||
solid: grabberSolid,
|
||||
visible: false,
|
||||
dashed: false,
|
||||
lineWidth: grabberLineWidth,
|
||||
drawInFront: true,
|
||||
borderSize: 1.4
|
||||
};
|
||||
|
@ -378,14 +375,12 @@ SelectionDisplay = (function() {
|
|||
solid: grabberSolid,
|
||||
visible: false,
|
||||
dashed: false,
|
||||
lineWidth: grabberLineWidth,
|
||||
drawInFront: true,
|
||||
borderSize: 1.4
|
||||
};
|
||||
|
||||
var spotLightLineProperties = {
|
||||
color: lightOverlayColor,
|
||||
lineWidth: 1.5
|
||||
color: lightOverlayColor
|
||||
};
|
||||
|
||||
var highlightBox = Overlays.addOverlay("cube", {
|
||||
|
@ -400,7 +395,6 @@ SelectionDisplay = (function() {
|
|||
solid: false,
|
||||
visible: false,
|
||||
dashed: true,
|
||||
lineWidth: 2.0,
|
||||
ignoreRayIntersection: true, // this never ray intersects
|
||||
drawInFront: true
|
||||
});
|
||||
|
@ -416,8 +410,7 @@ SelectionDisplay = (function() {
|
|||
alpha: 1,
|
||||
solid: false,
|
||||
visible: false,
|
||||
dashed: false,
|
||||
lineWidth: 1.0
|
||||
dashed: false
|
||||
});
|
||||
|
||||
var selectionBoxes = [];
|
||||
|
@ -466,7 +459,6 @@ SelectionDisplay = (function() {
|
|||
|
||||
// var normalLine = Overlays.addOverlay("line3d", {
|
||||
// visible: true,
|
||||
// lineWidth: 2.0,
|
||||
// start: { x: 0, y: 0, z: 0 },
|
||||
// end: { x: 0, y: 0, z: 0 },
|
||||
// color: { red: 255, green: 255, blue: 0 },
|
||||
|
@ -656,7 +648,6 @@ SelectionDisplay = (function() {
|
|||
|
||||
var xRailOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 1.0,
|
||||
start: Vec3.ZERO,
|
||||
end: Vec3.ZERO,
|
||||
color: {
|
||||
|
@ -668,7 +659,6 @@ SelectionDisplay = (function() {
|
|||
});
|
||||
var yRailOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 1.0,
|
||||
start: Vec3.ZERO,
|
||||
end: Vec3.ZERO,
|
||||
color: {
|
||||
|
@ -680,7 +670,6 @@ SelectionDisplay = (function() {
|
|||
});
|
||||
var zRailOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 1.0,
|
||||
start: Vec3.ZERO,
|
||||
end: Vec3.ZERO,
|
||||
color: {
|
||||
|
@ -693,7 +682,6 @@ SelectionDisplay = (function() {
|
|||
|
||||
var rotateZeroOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 2.0,
|
||||
start: Vec3.ZERO,
|
||||
end: Vec3.ZERO,
|
||||
color: {
|
||||
|
@ -706,7 +694,6 @@ SelectionDisplay = (function() {
|
|||
|
||||
var rotateCurrentOverlay = Overlays.addOverlay("line3d", {
|
||||
visible: false,
|
||||
lineWidth: 2.0,
|
||||
start: Vec3.ZERO,
|
||||
end: Vec3.ZERO,
|
||||
color: {
|
||||
|
@ -1788,7 +1775,6 @@ SelectionDisplay = (function() {
|
|||
y: distance,
|
||||
z: 1
|
||||
},
|
||||
lineWidth: 1.5,
|
||||
rotation: rotation,
|
||||
visible: true
|
||||
});
|
||||
|
@ -1994,7 +1980,6 @@ SelectionDisplay = (function() {
|
|||
solid: false,
|
||||
visible: false,
|
||||
dashed: false,
|
||||
lineWidth: 1.0,
|
||||
ignoreRayIntersection: true
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -189,7 +189,6 @@ function HighlightedEntity(id, entityProperties) {
|
|||
green: 0x91,
|
||||
blue: 0x29
|
||||
},
|
||||
lineWidth: 1.0,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene.
|
||||
});
|
||||
|
|
|
@ -350,8 +350,7 @@
|
|||
end: ZERO_VECTOR,
|
||||
color: { red: 255, green: 0, blue: 0},
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
visible: true
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -329,7 +329,6 @@
|
|||
y: 0,
|
||||
z: 0
|
||||
}, lineVectors[0]],
|
||||
lineWidth: 5,
|
||||
color: this.stringData.currentColor
|
||||
});
|
||||
|
||||
|
@ -339,7 +338,6 @@
|
|||
y: 0,
|
||||
z: 0
|
||||
}, lineVectors[1]],
|
||||
lineWidth: 5,
|
||||
color: this.stringData.currentColor
|
||||
});
|
||||
|
||||
|
|
|
@ -125,7 +125,6 @@ function createPreNotchString() {
|
|||
y: 0,
|
||||
z: 0
|
||||
}, downOffset)],
|
||||
lineWidth: 5,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
|
|
|
@ -450,7 +450,6 @@
|
|||
y: 0,
|
||||
z: 0
|
||||
}, downOffset)],
|
||||
lineWidth: 5,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
|
|
|
@ -427,7 +427,6 @@ MasterReset = function() {
|
|||
y: 0,
|
||||
z: 0
|
||||
}, downOffset)],
|
||||
lineWidth: 5,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
|
|
|
@ -346,8 +346,7 @@
|
|||
end: { x: 0, y: 0, z: 0 },
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
visible: true
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -266,7 +266,6 @@
|
|||
dimensions: { "x": 5, "y": 5, "z": 5 },
|
||||
ignoreForCollisions: 1,
|
||||
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
|
||||
lineWidth: 5,
|
||||
name: STRING_NAME,
|
||||
parentID: this.entityID,
|
||||
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
|
||||
|
@ -287,7 +286,6 @@
|
|||
resetStringToIdlePosition: function() {
|
||||
Entities.editEntity(this.stringID, {
|
||||
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
|
||||
lineWidth: 5,
|
||||
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
|
||||
localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 },
|
||||
});
|
||||
|
|
|
@ -99,7 +99,6 @@
|
|||
lifetime: 360,
|
||||
type: 'Line',
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
alpha: 0.5,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
|
|
|
@ -72,7 +72,6 @@ Laser = function (side) {
|
|||
}
|
||||
|
||||
laserLine = Overlays.addOverlay("line3d", {
|
||||
lineWidth: 5,
|
||||
alpha: 1.0,
|
||||
glow: 1.0,
|
||||
ignoreRayIntersection: true,
|
||||
|
|
|
@ -408,7 +408,6 @@ function getControllerLocation(controllerHand) {
|
|||
dimensions: { "x": 5, "y": 5, "z": 5 },
|
||||
ignoreForCollisions: 1,
|
||||
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
|
||||
lineWidth: 5,
|
||||
color: { red: 153, green: 102, blue: 51 },
|
||||
name: STRING_NAME,
|
||||
parentID: this.entityID,
|
||||
|
@ -430,7 +429,6 @@ function getControllerLocation(controllerHand) {
|
|||
resetStringToIdlePosition: function() {
|
||||
Entities.editEntity(this.stringID, {
|
||||
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
|
||||
lineWidth: 5,
|
||||
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
|
||||
localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 },
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue