mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into dk/3377
This commit is contained in:
commit
f23f882595
30 changed files with 721 additions and 185 deletions
|
@ -365,6 +365,28 @@ void AvatarMixer::handleRequestsDomainListDataPacket(QSharedPointer<ReceivedMess
|
|||
message->readPrimitive(&isRequesting);
|
||||
nodeData->setRequestsDomainListData(isRequesting);
|
||||
qCDebug(avatars) << "node" << nodeData->getNodeID() << "requestsDomainListData" << isRequesting;
|
||||
|
||||
// If we just opened the PAL...
|
||||
if (isRequesting) {
|
||||
// For each node in the NodeList...
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->eachMatchingNode(
|
||||
// Discover the valid nodes we're ignoring...
|
||||
[&](const SharedNodePointer& node)->bool {
|
||||
if (node->getUUID() != senderNode->getUUID() &&
|
||||
(nodeData->isRadiusIgnoring(node->getUUID()) ||
|
||||
senderNode->isIgnoringNodeWithID(node->getUUID()))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// ...For those nodes, reset the lastBroadcastTime to 0
|
||||
// so that the AvatarMixer will send Identity data to us
|
||||
[&](const SharedNodePointer& node) {
|
||||
nodeData->setLastBroadcastTime(node->getUUID(), 0);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto end = usecTimestampNow();
|
||||
|
@ -409,7 +431,31 @@ void AvatarMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message
|
|||
|
||||
void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
auto start = usecTimestampNow();
|
||||
senderNode->parseIgnoreRequestMessage(message);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
bool addToIgnore;
|
||||
message->readPrimitive(&addToIgnore);
|
||||
while (message->getBytesLeftToRead()) {
|
||||
// parse out the UUID being ignored from the packet
|
||||
QUuid ignoredUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||
// Reset the lastBroadcastTime for the ignored avatar to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignored avatar
|
||||
// to the ignorer if the ignorer unignores.
|
||||
nodeData->setLastBroadcastTime(ignoredUUID, 0);
|
||||
|
||||
// Reset the lastBroadcastTime for the ignorer (FROM THE PERSPECTIVE OF THE IGNORED) to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignorer
|
||||
// to the ignored if the ignorer unignores.
|
||||
auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID);
|
||||
AvatarMixerClientData* ignoredNodeData = reinterpret_cast<AvatarMixerClientData*>(ignoredNode->getLinkedData());
|
||||
ignoredNodeData->setLastBroadcastTime(senderNode->getUUID(), 0);
|
||||
|
||||
if (addToIgnore) {
|
||||
senderNode->addIgnoredNode(ignoredUUID);
|
||||
} else {
|
||||
senderNode->removeIgnoredNode(ignoredUUID);
|
||||
}
|
||||
}
|
||||
auto end = usecTimestampNow();
|
||||
_handleNodeIgnoreRequestPacketElapsedTime += (end - start);
|
||||
}
|
||||
|
|
|
@ -65,15 +65,6 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) {
|
|||
// compute the offset to the data payload
|
||||
return _avatar->parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead()));
|
||||
}
|
||||
|
||||
bool AvatarMixerClientData::checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid) {
|
||||
if (_hasReceivedFirstPacketsFrom.find(uuid) == _hasReceivedFirstPacketsFrom.end()) {
|
||||
_hasReceivedFirstPacketsFrom.insert(uuid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t AvatarMixerClientData::getLastBroadcastTime(const QUuid& nodeUUID) const {
|
||||
// return the matching PacketSequenceNumber, or the default if we don't have it
|
||||
auto nodeMatch = _lastBroadcastTimes.find(nodeUUID);
|
||||
|
@ -102,8 +93,8 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe
|
|||
} else {
|
||||
killPacket->writePrimitive(KillAvatarReason::YourAvatarEnteredTheirBubble);
|
||||
}
|
||||
setLastBroadcastTime(other->getUUID(), 0);
|
||||
DependencyManager::get<NodeList>()->sendUnreliablePacket(*killPacket, *self);
|
||||
_hasReceivedFirstPacketsFrom.erase(other->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,6 @@ public:
|
|||
const AvatarData* getConstAvatarData() const { return _avatar.get(); }
|
||||
AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; }
|
||||
|
||||
bool checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid);
|
||||
|
||||
uint16_t getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const;
|
||||
void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, uint16_t sequenceNumber)
|
||||
{ _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; }
|
||||
|
@ -63,8 +61,8 @@ public:
|
|||
|
||||
uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; }
|
||||
|
||||
HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
||||
void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); }
|
||||
uint64_t getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
||||
void flagIdentityChange() { _identityChangeTimestamp = usecTimestampNow(); }
|
||||
bool getAvatarSessionDisplayNameMustChange() const { return _avatarSessionDisplayNameMustChange; }
|
||||
void setAvatarSessionDisplayNameMustChange(bool set = true) { _avatarSessionDisplayNameMustChange = set; }
|
||||
|
||||
|
@ -139,7 +137,6 @@ private:
|
|||
|
||||
uint16_t _lastReceivedSequenceNumber { 0 };
|
||||
std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers;
|
||||
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
|
||||
std::unordered_map<QUuid, uint64_t> _lastBroadcastTimes;
|
||||
|
||||
// this is a map of the last time we encoded an "other" avatar for
|
||||
|
@ -147,7 +144,7 @@ private:
|
|||
std::unordered_map<QUuid, quint64> _lastOtherAvatarEncodeTime;
|
||||
std::unordered_map<QUuid, QVector<JointData>> _lastOtherAvatarSentJoints;
|
||||
|
||||
HRCTime _identityChangeTimestamp;
|
||||
uint64_t _identityChangeTimestamp;
|
||||
bool _avatarSessionDisplayNameMustChange{ false };
|
||||
|
||||
int _numAvatarsSentLastFrame = 0;
|
||||
|
|
|
@ -80,16 +80,6 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData,
|
|||
|
||||
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||
|
||||
// FIXME - There is some old logic (unchanged as of 2/17/17) that randomly decides to send an identity
|
||||
// packet. That logic had the following comment about the constants it uses...
|
||||
//
|
||||
// An 80% chance of sending a identity packet within a 5 second interval.
|
||||
// assuming 60 htz update rate.
|
||||
//
|
||||
// Assuming the calculation of the constant is in fact correct for 80% and 60hz and 5 seconds (an assumption
|
||||
// that I have not verified) then the constant is definitely wrong now, since we send at 45hz.
|
||||
const float IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
|
||||
|
||||
void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||
quint64 start = usecTimestampNow();
|
||||
|
||||
|
@ -137,14 +127,18 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
|||
// keep track of the number of other avatar frames skipped
|
||||
int numAvatarsWithSkippedFrames = 0;
|
||||
|
||||
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that are not in the view frustrum
|
||||
bool getsOutOfView = nodeData->getRequestsDomainListData();
|
||||
|
||||
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that they've ignored
|
||||
bool getsIgnoredByMe = getsOutOfView;
|
||||
// When this is true, the AvatarMixer will send Avatar data to a client
|
||||
// about avatars they've ignored or that are out of view
|
||||
bool PALIsOpen = nodeData->getRequestsDomainListData();
|
||||
|
||||
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them
|
||||
bool getsAnyIgnored = getsIgnoredByMe && node->getCanKick();
|
||||
bool getsAnyIgnored = PALIsOpen && node->getCanKick();
|
||||
|
||||
if (PALIsOpen) {
|
||||
// Increase minimumBytesPerAvatar if the PAL is open
|
||||
minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) +
|
||||
sizeof(AvatarDataPacket::AudioLoudness);
|
||||
}
|
||||
|
||||
// setup a PacketList for the avatarPackets
|
||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||
|
@ -222,13 +216,14 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
|||
// or that has ignored the viewing node
|
||||
if (!avatarNode->getLinkedData()
|
||||
|| avatarNode->getUUID() == node->getUUID()
|
||||
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !getsIgnoredByMe)
|
||||
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
||||
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
||||
shouldIgnore = true;
|
||||
} else {
|
||||
|
||||
// Check to see if the space bubble is enabled
|
||||
if (node->isIgnoreRadiusEnabled() || avatarNode->isIgnoreRadiusEnabled()) {
|
||||
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||
|
||||
// Define the scale of the box for the current other node
|
||||
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
||||
|
@ -306,16 +301,9 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
|||
|
||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||
|
||||
// make sure we send out identity packets to and from new arrivals.
|
||||
bool forceSend = !nodeData->checkAndSetHasReceivedFirstPacketsFrom(otherNode->getUUID());
|
||||
|
||||
// FIXME - this clause seems suspicious "... || otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp ..."
|
||||
if (!overBudget
|
||||
&& otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0
|
||||
&& (forceSend
|
||||
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|
||||
|| distribution(generator) < IDENTITY_SEND_PROBABILITY)) {
|
||||
|
||||
// If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO
|
||||
// the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A.
|
||||
if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) {
|
||||
identityBytesSent += sendIdentityPacket(otherNodeData, node);
|
||||
}
|
||||
|
||||
|
@ -335,9 +323,9 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
|||
if (overBudget) {
|
||||
overBudgetAvatars++;
|
||||
_stats.overBudgetAvatars++;
|
||||
detail = AvatarData::NoData;
|
||||
} else if (!isInView && !getsOutOfView) {
|
||||
detail = AvatarData::NoData;
|
||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
||||
} else if (!isInView) {
|
||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
||||
nodeData->incrementAvatarOutOfView();
|
||||
} else {
|
||||
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
||||
|
|
|
@ -5192,6 +5192,7 @@ void Application::updateWindowTitle() const {
|
|||
#endif
|
||||
_window->setWindowTitle(title);
|
||||
}
|
||||
|
||||
void Application::clearDomainOctreeDetails() {
|
||||
|
||||
// if we're about to quit, we really don't need to do any of these things...
|
||||
|
@ -5221,6 +5222,12 @@ void Application::clearDomainOctreeDetails() {
|
|||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||
|
||||
_recentlyClearedDomain = true;
|
||||
|
||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
||||
DependencyManager::get<AnimationCache>()->clearUnusedResources();
|
||||
DependencyManager::get<ModelCache>()->clearUnusedResources();
|
||||
DependencyManager::get<SoundCache>()->clearUnusedResources();
|
||||
DependencyManager::get<TextureCache>()->clearUnusedResources();
|
||||
}
|
||||
|
||||
void Application::domainChanged(const QString& domainHostname) {
|
||||
|
|
|
@ -329,7 +329,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo
|
|||
}
|
||||
|
||||
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||
AvatarHashMap::handleRemovedAvatar(removedAvatar);
|
||||
AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason);
|
||||
|
||||
// removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar
|
||||
// class in this context so we can call methods that don't exist at the base class.
|
||||
|
|
|
@ -62,7 +62,11 @@ namespace render {
|
|||
if (overlay->is3D()) {
|
||||
auto overlay3D = std::dynamic_pointer_cast<Base3DOverlay>(overlay);
|
||||
if (overlay3D->isAA())
|
||||
return (overlay3D->getDrawInFront() ? LAYER_3D_FRONT : LAYER_3D);
|
||||
if (overlay3D->getDrawInFront()) {
|
||||
return LAYER_3D_FRONT;
|
||||
} else {
|
||||
return LAYER_3D;
|
||||
}
|
||||
else
|
||||
return LAYER_NO_AA;
|
||||
} else {
|
||||
|
|
|
@ -186,6 +186,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
bool cullSmallChanges = (dataDetail == CullSmallData);
|
||||
bool sendAll = (dataDetail == SendAllData);
|
||||
bool sendMinimum = (dataDetail == MinimumData);
|
||||
bool sendPALMinimum = (dataDetail == PALMinimum);
|
||||
|
||||
lazyInitHeadData();
|
||||
|
||||
|
@ -222,24 +223,41 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
auto parentID = getParentID();
|
||||
|
||||
bool hasAvatarGlobalPosition = true; // always include global position
|
||||
bool hasAvatarOrientation = sendAll || rotationChangedSince(lastSentTime);
|
||||
bool hasAvatarBoundingBox = sendAll || avatarBoundingBoxChangedSince(lastSentTime);
|
||||
bool hasAvatarScale = sendAll || avatarScaleChangedSince(lastSentTime);
|
||||
bool hasLookAtPosition = sendAll || lookAtPositionChangedSince(lastSentTime);
|
||||
bool hasAudioLoudness = sendAll || audioLoudnessChangedSince(lastSentTime);
|
||||
bool hasSensorToWorldMatrix = sendAll || sensorToWorldMatrixChangedSince(lastSentTime);
|
||||
bool hasAdditionalFlags = sendAll || additionalFlagsChangedSince(lastSentTime);
|
||||
bool hasAvatarOrientation = false;
|
||||
bool hasAvatarBoundingBox = false;
|
||||
bool hasAvatarScale = false;
|
||||
bool hasLookAtPosition = false;
|
||||
bool hasAudioLoudness = false;
|
||||
bool hasSensorToWorldMatrix = false;
|
||||
bool hasAdditionalFlags = false;
|
||||
|
||||
// local position, and parent info only apply to avatars that are parented. The local position
|
||||
// and the parent info can change independently though, so we track their "changed since"
|
||||
// separately
|
||||
bool hasParentInfo = sendAll || parentInfoChangedSince(lastSentTime);
|
||||
bool hasAvatarLocalPosition = hasParent() && (sendAll ||
|
||||
tranlationChangedSince(lastSentTime) ||
|
||||
parentInfoChangedSince(lastSentTime));
|
||||
bool hasParentInfo = false;
|
||||
bool hasAvatarLocalPosition = false;
|
||||
|
||||
bool hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime));
|
||||
bool hasJointData = sendAll || !sendMinimum;
|
||||
bool hasFaceTrackerInfo = false;
|
||||
bool hasJointData = false;
|
||||
|
||||
if (sendPALMinimum) {
|
||||
hasAudioLoudness = true;
|
||||
} else {
|
||||
hasAvatarOrientation = sendAll || rotationChangedSince(lastSentTime);
|
||||
hasAvatarBoundingBox = sendAll || avatarBoundingBoxChangedSince(lastSentTime);
|
||||
hasAvatarScale = sendAll || avatarScaleChangedSince(lastSentTime);
|
||||
hasLookAtPosition = sendAll || lookAtPositionChangedSince(lastSentTime);
|
||||
hasAudioLoudness = sendAll || audioLoudnessChangedSince(lastSentTime);
|
||||
hasSensorToWorldMatrix = sendAll || sensorToWorldMatrixChangedSince(lastSentTime);
|
||||
hasAdditionalFlags = sendAll || additionalFlagsChangedSince(lastSentTime);
|
||||
hasParentInfo = sendAll || parentInfoChangedSince(lastSentTime);
|
||||
hasAvatarLocalPosition = hasParent() && (sendAll ||
|
||||
tranlationChangedSince(lastSentTime) ||
|
||||
parentInfoChangedSince(lastSentTime));
|
||||
|
||||
hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime));
|
||||
hasJointData = sendAll || !sendMinimum;
|
||||
}
|
||||
|
||||
// Leading flags, to indicate how much data is actually included in the packet...
|
||||
AvatarDataPacket::HasFlags packetStateFlags =
|
||||
|
|
|
@ -376,6 +376,7 @@ public:
|
|||
|
||||
typedef enum {
|
||||
NoData,
|
||||
PALMinimum,
|
||||
MinimumData,
|
||||
CullSmallData,
|
||||
IncludeSmallData,
|
||||
|
|
|
@ -154,14 +154,6 @@ const gpu::TexturePointer& TextureCache::getBlackTexture() {
|
|||
return _blackTexture;
|
||||
}
|
||||
|
||||
|
||||
const gpu::TexturePointer& TextureCache::getNormalFittingTexture() {
|
||||
if (!_normalFittingTexture) {
|
||||
_normalFittingTexture = getImageTexture(PathUtils::resourcesPath() + "images/normalFittingScale.dds");
|
||||
}
|
||||
return _normalFittingTexture;
|
||||
}
|
||||
|
||||
/// Extra data for creating textures.
|
||||
class TextureExtra {
|
||||
public:
|
||||
|
|
|
@ -124,9 +124,6 @@ public:
|
|||
/// Returns the a black texture (useful for a default).
|
||||
const gpu::TexturePointer& getBlackTexture();
|
||||
|
||||
// Returns a map used to compress the normals through a fitting scale algorithm
|
||||
const gpu::TexturePointer& getNormalFittingTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
static gpu::TexturePointer getImageTexture(const QString& path, Type type = Type::DEFAULT_TEXTURE, QVariantMap options = QVariantMap());
|
||||
|
||||
|
@ -151,7 +148,6 @@ private:
|
|||
gpu::TexturePointer _grayTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
gpu::TexturePointer _blackTexture;
|
||||
gpu::TexturePointer _normalFittingTexture;
|
||||
};
|
||||
|
||||
#endif // hifi_TextureCache_h
|
||||
|
|
|
@ -221,7 +221,7 @@ ResourceCache::ResourceCache(QObject* parent) : QObject(parent) {
|
|||
}
|
||||
|
||||
ResourceCache::~ResourceCache() {
|
||||
clearUnusedResource();
|
||||
clearUnusedResources();
|
||||
}
|
||||
|
||||
void ResourceCache::clearATPAssets() {
|
||||
|
@ -265,7 +265,7 @@ void ResourceCache::clearATPAssets() {
|
|||
|
||||
void ResourceCache::refreshAll() {
|
||||
// Clear all unused resources so we don't have to reload them
|
||||
clearUnusedResource();
|
||||
clearUnusedResources();
|
||||
resetResourceCounters();
|
||||
|
||||
QHash<QUrl, QWeakPointer<Resource>> resources;
|
||||
|
@ -418,7 +418,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
|
|||
}
|
||||
}
|
||||
|
||||
void ResourceCache::clearUnusedResource() {
|
||||
void ResourceCache::clearUnusedResources() {
|
||||
// the unused resources may themselves reference resources that will be added to the unused
|
||||
// list on destruction, so keep clearing until there are no references left
|
||||
QWriteLocker locker(&_unusedResourcesLock);
|
||||
|
|
|
@ -249,6 +249,7 @@ public:
|
|||
|
||||
void refreshAll();
|
||||
void refresh(const QUrl& url);
|
||||
void clearUnusedResources();
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
@ -298,7 +299,7 @@ protected:
|
|||
|
||||
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
|
||||
|
||||
/// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading
|
||||
/// \return true if the resource began loading, otherwise false if the resource is in the pending queue
|
||||
static bool attemptRequest(QSharedPointer<Resource> resource);
|
||||
|
@ -309,7 +310,6 @@ private:
|
|||
friend class Resource;
|
||||
|
||||
void reserveUnusedResource(qint64 resourceSize);
|
||||
void clearUnusedResource();
|
||||
void resetResourceCounters();
|
||||
void removeResource(const QUrl& url, qint64 size = 0);
|
||||
|
||||
|
|
|
@ -65,25 +65,4 @@ float packUnlit() {
|
|||
return FRAG_PACK_UNLIT;
|
||||
}
|
||||
|
||||
<!
|
||||
uniform sampler2D normalFittingMap;
|
||||
|
||||
vec3 bestFitNormal(vec3 normal) {
|
||||
vec3 absNorm = abs(normal);
|
||||
float maxNAbs = max(absNorm.z, max(absNorm.x, absNorm.y));
|
||||
|
||||
vec2 texcoord = (absNorm.z < maxNAbs ?
|
||||
(absNorm.y < maxNAbs ? absNorm.yz : absNorm.xz) :
|
||||
absNorm.xy);
|
||||
texcoord = (texcoord.x < texcoord.y ? texcoord.yx : texcoord.xy);
|
||||
texcoord.y /= texcoord.x;
|
||||
vec3 cN = normal / maxNAbs;
|
||||
|
||||
float fittingScale = texture(normalFittingMap, texcoord).a;
|
||||
cN *= fittingScale;
|
||||
|
||||
return (cN * 0.5 + 0.5);
|
||||
}
|
||||
!>
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -414,8 +414,6 @@ _nextID(0) {
|
|||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
);
|
||||
GeometryCache::_simpleTransparentPipeline =
|
||||
|
@ -424,8 +422,6 @@ _nextID(0) {
|
|||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
);
|
||||
GeometryCache::_simpleWirePipeline =
|
||||
|
@ -1770,7 +1766,6 @@ static void buildWebShader(const std::string& vertShaderText, const std::string&
|
|||
shaderPointerOut = gpu::Shader::createProgram(VS, PS);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING));
|
||||
gpu::Shader::makeProgram(*shaderPointerOut, slotBindings);
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
|
@ -1784,9 +1779,6 @@ static void buildWebShader(const std::string& vertShaderText, const std::string&
|
|||
|
||||
void GeometryCache::bindOpaqueWebBrowserProgram(gpu::Batch& batch, bool isAA) {
|
||||
batch.setPipeline(getOpaqueWebBrowserProgram(isAA));
|
||||
// Set a default normal map
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
|
||||
gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram(bool isAA) {
|
||||
|
@ -1802,9 +1794,6 @@ gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram(bool isAA) {
|
|||
|
||||
void GeometryCache::bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isAA) {
|
||||
batch.setPipeline(getTransparentWebBrowserProgram(isAA));
|
||||
// Set a default normal map
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
|
||||
gpu::PipelinePointer GeometryCache::getTransparentWebBrowserProgram(bool isAA) {
|
||||
|
@ -1827,9 +1816,6 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool tra
|
|||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
// Set a default normal map
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
|
||||
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) {
|
||||
|
@ -1846,7 +1832,6 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
|
|||
_unlitShader = gpu::Shader::createProgram(VS, PSUnlit);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING));
|
||||
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
||||
gpu::Shader::makeProgram(*_unlitShader, slotBindings);
|
||||
});
|
||||
|
|
|
@ -97,6 +97,8 @@ ShapeKey MeshPartPayload::getShapeKey() const {
|
|||
}
|
||||
|
||||
ShapeKey::Builder builder;
|
||||
builder.withMaterial();
|
||||
|
||||
if (drawMaterialKey.isTranslucent()) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
|
@ -478,6 +480,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
|||
}
|
||||
|
||||
ShapeKey::Builder builder;
|
||||
builder.withMaterial();
|
||||
|
||||
if (isTranslucent || _fadeState != FADE_COMPLETE) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
|
|
|
@ -75,7 +75,6 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) {
|
|||
// GPU jobs: Start preparing the primary, deferred and lighting buffer
|
||||
const auto primaryFramebuffer = addJob<PreparePrimaryFramebuffer>("PreparePrimaryBuffer");
|
||||
|
||||
// const auto fullFrameRangeTimer = addJob<BeginGPURangeTimer>("BeginRangeTimer");
|
||||
const auto opaqueRangeTimer = addJob<BeginGPURangeTimer>("BeginOpaqueRangeTimer", "DrawOpaques");
|
||||
|
||||
const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying();
|
||||
|
@ -154,21 +153,25 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) {
|
|||
const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer));
|
||||
addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
|
||||
|
||||
{ // DEbug the bounds of the rendered items, still look at the zbuffer
|
||||
addJob<DrawBounds>("DrawMetaBounds", metas);
|
||||
addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||
addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
||||
}
|
||||
|
||||
// Overlays
|
||||
const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying();
|
||||
const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying();
|
||||
addJob<DrawOverlay3D>("DrawOverlay3DOpaque", overlayOpaquesInputs, true);
|
||||
addJob<DrawOverlay3D>("DrawOverlay3DTransparent", overlayTransparentsInputs, false);
|
||||
|
||||
// Debugging stages
|
||||
{
|
||||
|
||||
|
||||
// Bounds do not draw on stencil buffer, so they must come last
|
||||
addJob<DrawBounds>("DrawMetaBounds", metas);
|
||||
{ // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer
|
||||
addJob<DrawBounds>("DrawOverlayOpaqueBounds", overlayOpaques);
|
||||
addJob<DrawBounds>("DrawOverlayTransparentBounds", overlayTransparents);
|
||||
|
||||
}
|
||||
|
||||
// Debugging stages
|
||||
{
|
||||
// Debugging Deferred buffer job
|
||||
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
|
||||
addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
|
||||
|
@ -208,9 +211,6 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) {
|
|||
|
||||
// Blit!
|
||||
addJob<Blit>("Blit", primaryFramebuffer);
|
||||
|
||||
// addJob<EndGPURangeTimer>("RangeTimer", fullFrameRangeTimer);
|
||||
|
||||
}
|
||||
|
||||
void BeginGPURangeTimer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) {
|
||||
|
|
|
@ -50,9 +50,13 @@
|
|||
|
||||
#include "overlay3D_vert.h"
|
||||
#include "overlay3D_frag.h"
|
||||
#include "overlay3D_model_frag.h"
|
||||
#include "overlay3D_model_translucent_frag.h"
|
||||
#include "overlay3D_translucent_frag.h"
|
||||
#include "overlay3D_unlit_frag.h"
|
||||
#include "overlay3D_translucent_unlit_frag.h"
|
||||
#include "overlay3D_model_unlit_frag.h"
|
||||
#include "overlay3D_model_translucent_unlit_frag.h"
|
||||
|
||||
|
||||
using namespace render;
|
||||
|
@ -70,15 +74,24 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch);
|
|||
|
||||
void initOverlay3DPipelines(ShapePlumber& plumber) {
|
||||
auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert));
|
||||
auto vertexModel = gpu::Shader::createVertex(std::string(model_vert));
|
||||
auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag));
|
||||
auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag));
|
||||
auto pixelUnlit = gpu::Shader::createPixel(std::string(overlay3D_unlit_frag));
|
||||
auto pixelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_translucent_unlit_frag));
|
||||
auto pixelModel = gpu::Shader::createPixel(std::string(overlay3D_model_frag));
|
||||
auto pixelModelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_frag));
|
||||
auto pixelModelUnlit = gpu::Shader::createPixel(std::string(overlay3D_model_unlit_frag));
|
||||
auto pixelModelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_unlit_frag));
|
||||
|
||||
auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel);
|
||||
auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent);
|
||||
auto unlitOpaqueProgram = gpu::Shader::createProgram(vertex, pixelUnlit);
|
||||
auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit);
|
||||
auto materialOpaqueProgram = gpu::Shader::createProgram(vertexModel, pixelModel);
|
||||
auto materialTranslucentProgram = gpu::Shader::createProgram(vertexModel, pixelModelTranslucent);
|
||||
auto materialUnlitOpaqueProgram = gpu::Shader::createProgram(vertexModel, pixelModel);
|
||||
auto materialUnlitTranslucentProgram = gpu::Shader::createProgram(vertexModel, pixelModelTranslucent);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool isCulled = (i & 1);
|
||||
|
@ -103,14 +116,20 @@ void initOverlay3DPipelines(ShapePlumber& plumber) {
|
|||
}
|
||||
|
||||
ShapeKey::Filter::Builder builder;
|
||||
|
||||
isCulled ? builder.withCullFace() : builder.withoutCullFace();
|
||||
isBiased ? builder.withDepthBias() : builder.withoutDepthBias();
|
||||
isOpaque ? builder.withOpaque() : builder.withTranslucent();
|
||||
|
||||
auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram;
|
||||
auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram;
|
||||
plumber.addPipeline(builder.withoutUnlit().build(), simpleProgram, state, &lightBatchSetter);
|
||||
plumber.addPipeline(builder.withUnlit().build(), unlitProgram, state, &batchSetter);
|
||||
auto materialProgram = isOpaque ? materialOpaqueProgram : materialTranslucentProgram;
|
||||
auto materialUnlitProgram = isOpaque ? materialUnlitOpaqueProgram : materialUnlitTranslucentProgram;
|
||||
|
||||
plumber.addPipeline(builder.withMaterial().build().key(), materialProgram, state, &lightBatchSetter);
|
||||
plumber.addPipeline(builder.withMaterial().withUnlit().build().key(), materialUnlitProgram, state, &batchSetter);
|
||||
plumber.addPipeline(builder.withoutUnlit().withoutMaterial().build().key(), simpleProgram, state, &lightBatchSetter);
|
||||
plumber.addPipeline(builder.withUnlit().withoutMaterial().build().key(), unlitProgram, state, &batchSetter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,78 +163,87 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
|
|||
// TODO: Refactor this to use a filter
|
||||
// Opaques
|
||||
addPipeline(
|
||||
Key::Builder(),
|
||||
Key::Builder().withMaterial(),
|
||||
modelVertex, modelPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withUnlit(),
|
||||
modelVertex, modelUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withUnlit(),
|
||||
modelVertex, modelUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTangents(),
|
||||
Key::Builder().withMaterial().withTangents(),
|
||||
modelNormalMapVertex, modelNormalMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSpecular(),
|
||||
Key::Builder().withMaterial().withSpecular(),
|
||||
modelVertex, modelSpecularMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withTangents().withSpecular(),
|
||||
modelNormalMapVertex, modelNormalSpecularMapPixel);
|
||||
// Translucents
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent(),
|
||||
modelVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent(),
|
||||
modelVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withMaterial().withTranslucent().withUnlit(),
|
||||
modelVertex, modelTranslucentUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withUnlit(),
|
||||
modelVertex, modelTranslucentUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withTangents(),
|
||||
Key::Builder().withMaterial().withTranslucent().withTangents(),
|
||||
modelNormalMapVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withSpecular(),
|
||||
Key::Builder().withMaterial().withTranslucent().withSpecular(),
|
||||
modelVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
|
||||
modelNormalMapVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
// FIXME: Ignore lightmap for translucents meshpart
|
||||
Key::Builder().withTranslucent().withLightmap(),
|
||||
Key::Builder().withMaterial().withTranslucent().withLightmap(),
|
||||
modelVertex, modelTranslucentPixel);
|
||||
// Lightmapped
|
||||
addPipeline(
|
||||
Key::Builder().withLightmap(),
|
||||
Key::Builder().withMaterial().withLightmap(),
|
||||
modelLightmapVertex, modelLightmapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withLightmap().withTangents(),
|
||||
Key::Builder().withMaterial().withLightmap().withTangents(),
|
||||
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withLightmap().withSpecular(),
|
||||
Key::Builder().withMaterial().withLightmap().withSpecular(),
|
||||
modelLightmapVertex, modelLightmapSpecularMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withLightmap().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withLightmap().withTangents().withSpecular(),
|
||||
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel);
|
||||
// Skinned
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned(),
|
||||
Key::Builder().withMaterial().withSkinned(),
|
||||
skinModelVertex, modelPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTangents(),
|
||||
Key::Builder().withMaterial().withSkinned().withTangents(),
|
||||
skinModelNormalMapVertex, modelNormalMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withSpecular(),
|
||||
Key::Builder().withMaterial().withSkinned().withSpecular(),
|
||||
skinModelVertex, modelSpecularMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(),
|
||||
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
|
||||
// Skinned and Translucent
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTranslucent(),
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent(),
|
||||
skinModelVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTranslucent().withTangents(),
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
|
||||
skinModelNormalMapVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTranslucent().withSpecular(),
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
|
||||
skinModelVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTranslucent().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
|
||||
skinModelNormalMapVertex, modelTranslucentPixel);
|
||||
// Depth-only
|
||||
addPipeline(
|
||||
|
@ -244,32 +272,32 @@ void initForwardPipelines(render::ShapePlumber& plumber) {
|
|||
auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3);
|
||||
// Opaques
|
||||
addPipeline(
|
||||
Key::Builder(),
|
||||
Key::Builder().withMaterial(),
|
||||
modelVertex, modelPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withUnlit(),
|
||||
Key::Builder().withMaterial().withUnlit(),
|
||||
modelVertex, modelUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTangents(),
|
||||
Key::Builder().withMaterial().withTangents(),
|
||||
modelNormalMapVertex, modelNormalMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSpecular(),
|
||||
Key::Builder().withMaterial().withSpecular(),
|
||||
modelVertex, modelSpecularMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withTangents().withSpecular(),
|
||||
modelNormalMapVertex, modelNormalSpecularMapPixel);
|
||||
// Skinned
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned(),
|
||||
Key::Builder().withMaterial().withSkinned(),
|
||||
skinModelVertex, modelPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTangents(),
|
||||
Key::Builder().withMaterial().withSkinned().withTangents(),
|
||||
skinModelNormalMapVertex, modelNormalMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withSpecular(),
|
||||
Key::Builder().withMaterial().withSkinned().withSpecular(),
|
||||
skinModelVertex, modelSpecularMapPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withSkinned().withTangents().withSpecular(),
|
||||
Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(),
|
||||
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
|
||||
}
|
||||
|
||||
|
@ -319,9 +347,6 @@ void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
|
|||
// Set a default albedo map
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
// Set a default normal map
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING,
|
||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
|
||||
// Set a default material
|
||||
if (pipeline.locations->materialBufferUnit >= 0) {
|
||||
|
|
88
libraries/render-utils/src/overlay3D_model.slf
Normal file
88
libraries/render-utils/src/overlay3D_model.slf
Normal file
|
@ -0,0 +1,88 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// overlay3D.slf
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/16/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
<$declareEvalSkyboxGlobalColor()$>
|
||||
|
||||
<@include model/Material.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardCameraTransform()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec2 _texCoord1;
|
||||
in vec4 _position;
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$>
|
||||
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
float metallic = getMaterialMetallic(mat);
|
||||
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
|
||||
if (metallic <= 0.5) {
|
||||
metallic = 0.0;
|
||||
} else {
|
||||
fresnel = albedo;
|
||||
metallic = 1.0;
|
||||
}
|
||||
|
||||
float roughness = getMaterialRoughness(mat);
|
||||
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
|
||||
|
||||
vec3 emissive = getMaterialEmissive(mat);
|
||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
//vec3 fragNormal = normalize(_normal);
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragNormal;
|
||||
<$transformEyeToWorldDir(cam, _normal, fragNormal)$>;
|
||||
|
||||
vec4 color = vec4(evalSkyboxGlobalColor(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
occlusionTex,
|
||||
fragPosition,
|
||||
fragNormal,
|
||||
albedo,
|
||||
fresnel,
|
||||
metallic,
|
||||
roughness),
|
||||
opacity);
|
||||
|
||||
// And emissive
|
||||
color.rgb += emissive * isEmissiveEnabled();
|
||||
|
||||
// Apply standard tone mapping
|
||||
_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);
|
||||
}
|
83
libraries/render-utils/src/overlay3D_model_translucent.slf
Normal file
83
libraries/render-utils/src/overlay3D_model_translucent.slf
Normal file
|
@ -0,0 +1,83 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// overlay3D_model_transparent.slf
|
||||
//
|
||||
// Created by Sam Gateau on 2/27/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
|
||||
//
|
||||
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
<$declareEvalGlobalLightingAlphaBlended()$>
|
||||
|
||||
<@include model/Material.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardCameraTransform()$>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec2 _texCoord1;
|
||||
in vec4 _position;
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$>
|
||||
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
float metallic = getMaterialMetallic(mat);
|
||||
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
|
||||
if (metallic <= 0.5) {
|
||||
metallic = 0.0;
|
||||
} else {
|
||||
fresnel = albedo;
|
||||
metallic = 1.0;
|
||||
}
|
||||
|
||||
float roughness = getMaterialRoughness(mat);
|
||||
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
|
||||
|
||||
vec3 emissive = getMaterialEmissive(mat);
|
||||
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
|
||||
|
||||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
vec3 fragNormal;
|
||||
<$transformEyeToWorldDir(cam, _normal, fragNormal)$>
|
||||
|
||||
vec4 color = vec4(evalGlobalLightingAlphaBlended(
|
||||
cam._viewInverse,
|
||||
1.0,
|
||||
occlusionTex,
|
||||
fragPosition,
|
||||
fragNormal,
|
||||
albedo,
|
||||
fresnel,
|
||||
metallic,
|
||||
emissive,
|
||||
roughness, opacity),
|
||||
opacity);
|
||||
|
||||
// Apply standard tone mapping
|
||||
_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// overlay3D-model_transparent_unlit.slf
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 2/28/2017.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include LightingModel.slh@>
|
||||
<@include model/Material.slh@>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
vec4 color = vec4(albedo * isUnlitEnabled(), opacity);
|
||||
|
||||
_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);
|
||||
}
|
44
libraries/render-utils/src/overlay3D_model_unlit.slf
Normal file
44
libraries/render-utils/src/overlay3D_model_unlit.slf
Normal file
|
@ -0,0 +1,44 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// overlay3D-model_unlit.slf
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 2/28/2017.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include LightingModel.slh@>
|
||||
<@include model/Material.slh@>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
vec4 color = vec4(albedo * isUnlitEnabled(), opacity);
|
||||
|
||||
_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);
|
||||
}
|
|
@ -20,8 +20,6 @@ void renderItems(const SceneContextPointer& sceneContext, const RenderContextPoi
|
|||
void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1);
|
||||
void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1);
|
||||
|
||||
|
||||
|
||||
class DrawLightConfig : public Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged)
|
||||
|
|
|
@ -39,6 +39,10 @@ void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit
|
|||
}
|
||||
} else {
|
||||
// Add the brand new pipeline and cache its location in the lib
|
||||
auto precedent = _pipelineMap.find(key);
|
||||
if (precedent != _pipelineMap.end()) {
|
||||
qCDebug(renderlogging) << "Key already assigned: " << key;
|
||||
}
|
||||
_pipelineMap.insert(PipelineMap::value_type(key, pipeline));
|
||||
}
|
||||
}
|
||||
|
@ -65,16 +69,11 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
|||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto locations = std::make_shared<Locations>();
|
||||
locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||
if (program->getTextures().findLocation("normalFittingMap") > -1) {
|
||||
locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||
|
||||
}
|
||||
locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap");
|
||||
locations->roughnessTextureUnit = program->getTextures().findLocation("roughnessMap");
|
||||
locations->normalTextureUnit = program->getTextures().findLocation("normalMap");
|
||||
|
|
|
@ -22,13 +22,13 @@ namespace render {
|
|||
class ShapeKey {
|
||||
public:
|
||||
enum FlagBit {
|
||||
TRANSLUCENT = 0,
|
||||
MATERIAL = 0,
|
||||
TRANSLUCENT,
|
||||
LIGHTMAP,
|
||||
TANGENTS,
|
||||
SPECULAR,
|
||||
UNLIT,
|
||||
SKINNED,
|
||||
STEREO,
|
||||
DEPTH_ONLY,
|
||||
DEPTH_BIAS,
|
||||
WIREFRAME,
|
||||
|
@ -53,13 +53,13 @@ public:
|
|||
|
||||
ShapeKey build() const { return ShapeKey{_flags}; }
|
||||
|
||||
Builder& withMaterial() { _flags.set(MATERIAL); return (*this); }
|
||||
Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); }
|
||||
Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); }
|
||||
Builder& withTangents() { _flags.set(TANGENTS); return (*this); }
|
||||
Builder& withSpecular() { _flags.set(SPECULAR); return (*this); }
|
||||
Builder& withUnlit() { _flags.set(UNLIT); return (*this); }
|
||||
Builder& withSkinned() { _flags.set(SKINNED); return (*this); }
|
||||
Builder& withStereo() { _flags.set(STEREO); return (*this); }
|
||||
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); }
|
||||
Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); }
|
||||
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
|
||||
|
@ -89,6 +89,9 @@ public:
|
|||
|
||||
Filter build() const { return Filter(_flags, _mask); }
|
||||
|
||||
Builder& withMaterial() { _flags.set(MATERIAL); _mask.set(MATERIAL); return (*this); }
|
||||
Builder& withoutMaterial() { _flags.reset(MATERIAL); _mask.set(MATERIAL); return (*this); }
|
||||
|
||||
Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
||||
Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
||||
|
||||
|
@ -107,9 +110,6 @@ public:
|
|||
Builder& withSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
Builder& withoutSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
|
||||
Builder& withStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); }
|
||||
Builder& withoutStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); }
|
||||
|
||||
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||
Builder& withoutDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||
|
||||
|
@ -128,19 +128,20 @@ public:
|
|||
Flags _mask{0};
|
||||
};
|
||||
Filter(const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {}
|
||||
ShapeKey key() const { return ShapeKey(_flags); }
|
||||
protected:
|
||||
friend class ShapePlumber;
|
||||
Flags _flags{0};
|
||||
Flags _mask{0};
|
||||
};
|
||||
|
||||
bool useMaterial() const { return _flags[MATERIAL]; }
|
||||
bool hasLightmap() const { return _flags[LIGHTMAP]; }
|
||||
bool hasTangents() const { return _flags[TANGENTS]; }
|
||||
bool hasSpecular() const { return _flags[SPECULAR]; }
|
||||
bool isUnlit() const { return _flags[UNLIT]; }
|
||||
bool isTranslucent() const { return _flags[TRANSLUCENT]; }
|
||||
bool isSkinned() const { return _flags[SKINNED]; }
|
||||
bool isStereo() const { return _flags[STEREO]; }
|
||||
bool isDepthOnly() const { return _flags[DEPTH_ONLY]; }
|
||||
bool isDepthBiased() const { return _flags[DEPTH_BIAS]; }
|
||||
bool isWireFrame() const { return _flags[WIREFRAME]; }
|
||||
|
@ -170,13 +171,13 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) {
|
|||
debug << "[ShapeKey: OWN_PIPELINE]";
|
||||
} else {
|
||||
debug << "[ShapeKey:"
|
||||
<< "useMaterial:" << key.useMaterial()
|
||||
<< "hasLightmap:" << key.hasLightmap()
|
||||
<< "hasTangents:" << key.hasTangents()
|
||||
<< "hasSpecular:" << key.hasSpecular()
|
||||
<< "isUnlit:" << key.isUnlit()
|
||||
<< "isTranslucent:" << key.isTranslucent()
|
||||
<< "isSkinned:" << key.isSkinned()
|
||||
<< "isStereo:" << key.isStereo()
|
||||
<< "isDepthOnly:" << key.isDepthOnly()
|
||||
<< "isDepthBiased:" << key.isDepthBiased()
|
||||
<< "isWireFrame:" << key.isWireFrame()
|
||||
|
@ -213,8 +214,6 @@ public:
|
|||
OCCLUSION,
|
||||
SCATTERING,
|
||||
LIGHT_AMBIENT,
|
||||
|
||||
NORMAL_FITTING = 10,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -226,7 +225,6 @@ public:
|
|||
int metallicTextureUnit;
|
||||
int emissiveTextureUnit;
|
||||
int occlusionTextureUnit;
|
||||
int normalFittingMapUnit;
|
||||
int lightingModelBufferUnit;
|
||||
int skinClusterBufferUnit;
|
||||
int materialBufferUnit;
|
||||
|
|
|
@ -159,13 +159,33 @@ Column {
|
|||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Column {
|
||||
id: metas
|
||||
CheckBox {
|
||||
text: "Draw Meta Bounds"
|
||||
text: "Metas"
|
||||
checked: Render.getConfig("DrawMetaBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Opaques"
|
||||
checked: Render.getConfig("DrawOpaqueBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawOpaqueBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Transparents"
|
||||
checked: Render.getConfig("DrawTransparentBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawTransparentBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Overlay Opaques"
|
||||
checked: Render.getConfig("DrawOverlayOpaqueBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawOverlayOpaqueBounds")["enabled"] = checked }
|
||||
}
|
||||
CheckBox {
|
||||
text: "Overlay Transparents"
|
||||
checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"]
|
||||
onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
BIN
scripts/system/assets/sounds/entitySnap.wav
Normal file
BIN
scripts/system/assets/sounds/entitySnap.wav
Normal file
Binary file not shown.
|
@ -3552,7 +3552,6 @@ function MyController(hand) {
|
|||
// we appear to be holding something and this script isn't in a state that would be holding something.
|
||||
// unhook it. if we previously took note of this entity's parent, put it back where it was. This
|
||||
// works around some problems that happen when more than one hand or avatar is passing something around.
|
||||
print("disconnecting stray child of hand: (" + _this.hand + ") " + childID);
|
||||
if (_this.previousParentID[childID]) {
|
||||
var previousParentID = _this.previousParentID[childID];
|
||||
var previousParentJointIndex = _this.previousParentJointIndex[childID];
|
||||
|
@ -3570,13 +3569,21 @@ function MyController(hand) {
|
|||
}
|
||||
_this.previouslyUnhooked[childID] = now;
|
||||
|
||||
// we don't know if it's an entity or an overlay
|
||||
if (Overlays.getProperty(childID, "grabbable")) {
|
||||
// only auto-unhook overlays that were flagged as grabbable. this avoids unhooking overlays
|
||||
// used in tutorial.
|
||||
Overlays.editOverlay(childID, {
|
||||
parentID: previousParentID,
|
||||
parentJointIndex: previousParentJointIndex
|
||||
});
|
||||
}
|
||||
Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
|
||||
Overlays.editOverlay(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex });
|
||||
|
||||
} else {
|
||||
Entities.editEntity(childID, { parentID: NULL_UUID });
|
||||
Overlays.editOverlay(childID, { parentID: NULL_UUID });
|
||||
if (Overlays.getProperty(childID, "grabbable")) {
|
||||
Overlays.editOverlay(childID, { parentID: NULL_UUID });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
151
scripts/tutorials/entity_scripts/magneticBlock.js
Normal file
151
scripts/tutorials/entity_scripts/magneticBlock.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
//
|
||||
// magneticBlock.js
|
||||
//
|
||||
// Created by Matti Lahtinen 4/3/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
|
||||
//
|
||||
// Makes the entity the script is bound to connect to nearby, similarly sized entities, like a magnet.
|
||||
|
||||
(function() {
|
||||
var SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs"));
|
||||
var RANGE_MULTIPLER = 1.5;
|
||||
var MAX_SCALE = 2;
|
||||
var MIN_SCALE = 0.5;
|
||||
|
||||
// Helper for detecting nearby objects near entityProperties, with the scale calculated by the dimensions of the object.
|
||||
function findEntitiesInRange(entityProperties) {
|
||||
var dimensions = entityProperties.dimensions;
|
||||
// Average of the dimensions instead of full value.
|
||||
return Entities.findEntities(entityProperties.position,
|
||||
((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER);
|
||||
}
|
||||
|
||||
function getNearestValidEntityProperties(releasedProperties) {
|
||||
var entities = findEntitiesInRange(releasedProperties);
|
||||
var nearestEntity = null;
|
||||
var nearest = Number.MAX_VALUE - 1;
|
||||
var releaseSize = Vec3.length(releasedProperties.dimensions);
|
||||
entities.forEach(function(entityId) {
|
||||
if (entityId !== releasedProperties.id) {
|
||||
var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']);
|
||||
var distance = Vec3.distance(releasedProperties.position, entity.position);
|
||||
var scale = releaseSize / Vec3.length(entity.dimensions);
|
||||
|
||||
if (distance < nearest && (scale >= MIN_SCALE && scale <= MAX_SCALE)) {
|
||||
nearestEntity = entity;
|
||||
nearest = distance;
|
||||
}
|
||||
}
|
||||
});
|
||||
return nearestEntity;
|
||||
}
|
||||
// Create the 'class'
|
||||
function MagneticBlock() {}
|
||||
// Bind pre-emptive events
|
||||
MagneticBlock.prototype = {
|
||||
/*
|
||||
When script is bound to an entity, preload is the first callback called with the entityID.
|
||||
It will behave as the constructor
|
||||
*/
|
||||
preload: function(id) {
|
||||
/*
|
||||
We will now override any existing userdata with the grabbable property.
|
||||
Only retrieving userData
|
||||
*/
|
||||
var entityProperties = Entities.getEntityProperties(id, ['userData']);
|
||||
var userData = {
|
||||
grabbableKey: {}
|
||||
};
|
||||
// Check if existing userData field exists.
|
||||
if (entityProperties.userData && entityProperties.userData.length > 0) {
|
||||
try {
|
||||
userData = JSON.parse(entityProperties.userData);
|
||||
if (!userData.grabbableKey) {
|
||||
userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData.
|
||||
}
|
||||
} catch (e) {
|
||||
// if user data is not valid json, we will simply overwrite it.
|
||||
}
|
||||
}
|
||||
// Object must be triggerable inorder to bind releaseGrabEvent
|
||||
userData.grabbableKey.grabbable = true;
|
||||
|
||||
// Apply the new properties to entity of id
|
||||
Entities.editEntity(id, {
|
||||
userData: JSON.stringify(userData)
|
||||
});
|
||||
Script.scriptEnding.connect(function() {
|
||||
Script.removeEventHandler(id, "releaseGrab", this.releaseGrab);
|
||||
});
|
||||
},
|
||||
releaseGrab: function(entityId) {
|
||||
// Release grab is called with entityId,
|
||||
var released = Entities.getEntityProperties(entityId, ["position", "rotation", "dimensions"]);
|
||||
var target = getNearestValidEntityProperties(released);
|
||||
if (target !== null) {
|
||||
// We found nearest, now lets do the snap calculations
|
||||
// Plays the snap sound between the two objects.
|
||||
Audio.playSound(SNAPSOUND_SOURCE, {
|
||||
volume: 1,
|
||||
position: Vec3.mix(target.position, released.position, 0.5)
|
||||
});
|
||||
// Check Nearest Axis
|
||||
var difference = Vec3.subtract(released.position, target.position);
|
||||
var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference);
|
||||
|
||||
var abs = {
|
||||
x: Math.abs(relativeDifference.x),
|
||||
y: Math.abs(relativeDifference.y),
|
||||
z: Math.abs(relativeDifference.z)
|
||||
};
|
||||
// Check what value is greater. and lock down to that axis.
|
||||
var newRelative = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
if (abs.x >= abs.y && abs.x >= abs.z) {
|
||||
newRelative.x = target.dimensions.x / 2 + released.dimensions.x / 2;
|
||||
if (relativeDifference.x < 0) {
|
||||
newRelative.x = -newRelative.x;
|
||||
}
|
||||
} else if (abs.y >= abs.x && abs.y >= abs.z) {
|
||||
newRelative.y = target.dimensions.y / 2 + released.dimensions.y / 2;
|
||||
if (relativeDifference.y < 0) {
|
||||
newRelative.y = -newRelative.y;
|
||||
}
|
||||
} else if (abs.z >= abs.x && abs.z >= abs.y) {
|
||||
newRelative.z = target.dimensions.z / 2 + released.dimensions.z / 2;
|
||||
if (relativeDifference.z < 0) {
|
||||
newRelative.z = -newRelative.z;
|
||||
}
|
||||
}
|
||||
// Can be expanded upon to work in nearest 90 degree rotation as well, but was not in spec.
|
||||
var newPosition = Vec3.multiplyQbyV(target.rotation, newRelative);
|
||||
Entities.editEntity(entityId, {
|
||||
// Script relies on the registrationPoint being at the very center of the object. Thus override.
|
||||
registrationPoint: {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
z: 0.5
|
||||
},
|
||||
rotation: target.rotation,
|
||||
position: Vec3.sum(target.position, newPosition)
|
||||
});
|
||||
// Script relies on the registrationPoint being at the very center of the object. Thus override.
|
||||
Entities.editEntity(target.id, {
|
||||
registrationPoint: {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
z: 0.5
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return new MagneticBlock();
|
||||
});
|
72
scripts/tutorials/makeBlocks.js
Normal file
72
scripts/tutorials/makeBlocks.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// makeBlocks.js
|
||||
//
|
||||
// Created by Matti Lahtinen 4/3/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
|
||||
//
|
||||
// Creates multiple "magnetic" blocks with random colors that users clones of and snap together.
|
||||
|
||||
|
||||
(function() {
|
||||
var MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum.
|
||||
var MIN_COLOR_VALUE = 127;
|
||||
var SIZE = 0.3;
|
||||
var LIFETIME = 600;
|
||||
var VERTICAL_OFFSET = -0.25;
|
||||
var ROWS = 3;
|
||||
var COLUMNS = 3;
|
||||
// Random Pastel Generator based on Piper's script
|
||||
function newColor() {
|
||||
return {
|
||||
red: randomPastelRGBComponent(),
|
||||
green: randomPastelRGBComponent(),
|
||||
blue: randomPastelRGBComponent()
|
||||
};
|
||||
}
|
||||
// Helper functions.
|
||||
function randomPastelRGBComponent() {
|
||||
return Math.floor(Math.random() * MAX_RGB_COMPONENT_VALUE) + MIN_COLOR_VALUE;
|
||||
}
|
||||
|
||||
var SCRIPT_URL = Script.resolvePath("./entity_scripts/magneticBlock.js");
|
||||
|
||||
var frontVector = Quat.getFront(MyAvatar.orientation);
|
||||
frontVector.y += VERTICAL_OFFSET;
|
||||
for (var x = 0; x < COLUMNS; x++) {
|
||||
for (var y = 0; y < ROWS; y++) {
|
||||
|
||||
var frontOffset = {
|
||||
x: 0,
|
||||
y: SIZE * y + SIZE,
|
||||
z: SIZE * x + SIZE
|
||||
};
|
||||
|
||||
Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "MagneticBlock-" + y + '-' + x,
|
||||
dimensions: {
|
||||
x: SIZE,
|
||||
y: SIZE,
|
||||
z: SIZE
|
||||
},
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
cloneable: true,
|
||||
grabbable: true,
|
||||
cloneLifetime: LIFETIME,
|
||||
cloneLimit: 9999
|
||||
}
|
||||
}),
|
||||
position: Vec3.sum(MyAvatar.position, Vec3.sum(frontOffset, frontVector)),
|
||||
color: newColor(),
|
||||
script: SCRIPT_URL
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Script.stop();
|
||||
})();
|
Loading…
Reference in a new issue