mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 07:03:44 +02:00
Merge commit '5f08ed5027a8904242a47b17e994ab4f309e3930' into avatar-mixer-scaling
Merge of Samuel's change to use simple sort instead of priority queue
This commit is contained in:
commit
6ae2ca1576
13 changed files with 110 additions and 86 deletions
|
@ -437,10 +437,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
||||||
while (!sortedAvatars.empty()) {
|
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
||||||
const Node* otherNode = sortedAvatars.top().getNode();
|
for (const auto& sortedAvatar : sortedAvatarVector) {
|
||||||
auto lastEncodeForOther = sortedAvatars.top().getTimestamp();
|
const auto& avatarData = sortedAvatar.getAvatar();
|
||||||
sortedAvatars.pop();
|
const Node* otherNode = sortedAvatar.getNode();
|
||||||
|
auto lastEncodeForOther = sortedAvatar.getTimestamp();
|
||||||
remainingAvatars--;
|
remainingAvatars--;
|
||||||
|
|
||||||
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
|
|
|
@ -206,6 +206,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
}
|
}
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
|
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
||||||
|
|
||||||
// process in sorted order
|
// process in sorted order
|
||||||
uint64_t startTime = usecTimestampNow();
|
uint64_t startTime = usecTimestampNow();
|
||||||
|
@ -216,8 +217,8 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
|
|
||||||
render::Transaction renderTransaction;
|
render::Transaction renderTransaction;
|
||||||
workload::Transaction workloadTransaction;
|
workload::Transaction workloadTransaction;
|
||||||
while (!sortedAvatars.empty()) {
|
for (auto it = sortedAvatarVector.begin(); it != sortedAvatarVector.end(); ++it) {
|
||||||
const SortableAvatar& sortData = sortedAvatars.top();
|
const SortableAvatar& sortData = *it;
|
||||||
const auto avatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
|
const auto avatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
|
||||||
|
|
||||||
// TODO: to help us scale to more avatars it would be nice to not have to poll orb state here
|
// TODO: to help us scale to more avatars it would be nice to not have to poll orb state here
|
||||||
|
@ -231,7 +232,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
|
|
||||||
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
||||||
if (ignoring) {
|
if (ignoring) {
|
||||||
sortedAvatars.pop();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,26 +260,17 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
// --> some avatar velocity measurements may be a little off
|
// --> some avatar velocity measurements may be a little off
|
||||||
|
|
||||||
// no time to simulate, but we take the time to count how many were tragically missed
|
// no time to simulate, but we take the time to count how many were tragically missed
|
||||||
bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
while (it != sortedAvatarVector.end()) {
|
||||||
if (!inView) {
|
const SortableAvatar& newSortData = *it;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (inView && avatar->hasNewJointData()) {
|
|
||||||
numAVatarsNotUpdated++;
|
|
||||||
}
|
|
||||||
sortedAvatars.pop();
|
|
||||||
while (inView && !sortedAvatars.empty()) {
|
|
||||||
const SortableAvatar& newSortData = sortedAvatars.top();
|
|
||||||
const auto newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
|
const auto newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
|
||||||
inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
bool inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||||
if (inView && newAvatar->hasNewJointData()) {
|
if (inView && newAvatar->hasNewJointData()) {
|
||||||
numAVatarsNotUpdated++;
|
numAVatarsNotUpdated++;
|
||||||
}
|
}
|
||||||
sortedAvatars.pop();
|
++it;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sortedAvatars.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_shouldRender) {
|
if (_shouldRender) {
|
||||||
|
|
|
@ -29,20 +29,23 @@ OtherAvatar::~OtherAvatar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OtherAvatar::removeOrb() {
|
void OtherAvatar::removeOrb() {
|
||||||
if (qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) {
|
if (!_otherAvatarOrbMeshPlaceholderID.isNull()) {
|
||||||
qApp->getOverlays().deleteOverlay(_otherAvatarOrbMeshPlaceholderID);
|
qApp->getOverlays().deleteOverlay(_otherAvatarOrbMeshPlaceholderID);
|
||||||
|
_otherAvatarOrbMeshPlaceholderID = UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OtherAvatar::updateOrbPosition() {
|
void OtherAvatar::updateOrbPosition() {
|
||||||
if (_otherAvatarOrbMeshPlaceholder != nullptr) {
|
if (_otherAvatarOrbMeshPlaceholder != nullptr) {
|
||||||
_otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition());
|
_otherAvatarOrbMeshPlaceholder->setWorldPosition(getHead()->getPosition());
|
||||||
|
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
|
||||||
|
_otherAvatarOrbMeshPlaceholderID = qApp->getOverlays().addOverlay(_otherAvatarOrbMeshPlaceholder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OtherAvatar::createOrb() {
|
void OtherAvatar::createOrb() {
|
||||||
if (_otherAvatarOrbMeshPlaceholderID == UNKNOWN_OVERLAY_ID ||
|
if (_otherAvatarOrbMeshPlaceholderID.isNull()) {
|
||||||
!qApp->getOverlays().isAddedOverlay(_otherAvatarOrbMeshPlaceholderID)) {
|
|
||||||
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
|
_otherAvatarOrbMeshPlaceholder = std::make_shared<Sphere3DOverlay>();
|
||||||
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
|
_otherAvatarOrbMeshPlaceholder->setAlpha(1.0f);
|
||||||
_otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF });
|
_otherAvatarOrbMeshPlaceholder->setColor({ 0xFF, 0x00, 0xFF });
|
||||||
|
|
|
@ -527,8 +527,8 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the source hasn't been written yet, defer processing of this route
|
// If the source hasn't been written yet, defer processing of this route
|
||||||
auto source = route->source;
|
auto& source = route->source;
|
||||||
auto sourceInput = source->getInput();
|
auto& sourceInput = source->getInput();
|
||||||
if (sourceInput.device == STANDARD_DEVICE && !force && source->writeable()) {
|
if (sourceInput.device == STANDARD_DEVICE && !force && source->writeable()) {
|
||||||
if (debugRoutes && route->debug) {
|
if (debugRoutes && route->debug) {
|
||||||
qCDebug(controllers) << "Source not yet written, deferring";
|
qCDebug(controllers) << "Source not yet written, deferring";
|
||||||
|
@ -559,7 +559,7 @@ bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto destination = route->destination;
|
auto& destination = route->destination;
|
||||||
// THis could happen if the route destination failed to create
|
// THis could happen if the route destination failed to create
|
||||||
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
|
// FIXME: Maybe do not create the route if the destination failed and avoid this case ?
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
|
|
|
@ -405,11 +405,14 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
||||||
|
|
||||||
// process the sorted renderables
|
// process the sorted renderables
|
||||||
size_t numSorted = sortedRenderables.size();
|
size_t numSorted = sortedRenderables.size();
|
||||||
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
|
const auto& sortedRenderablesVector = sortedRenderables.getSortedVector();
|
||||||
const auto renderable = sortedRenderables.top().getRenderer();
|
for (const auto& sortedRenderable : sortedRenderablesVector) {
|
||||||
|
if (usecTimestampNow() > expiry) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const auto& renderable = sortedRenderable.getRenderer();
|
||||||
renderable->updateInScene(scene, transaction);
|
renderable->updateInScene(scene, transaction);
|
||||||
_renderablesToUpdate.erase(renderable->getEntity()->getID());
|
_renderablesToUpdate.erase(renderable->getEntity()->getID());
|
||||||
sortedRenderables.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute average per-renderable update cost
|
// compute average per-renderable update cost
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <glm/detail/type_vec.hpp>
|
#include <glm/detail/type_vec.hpp>
|
||||||
|
|
||||||
#include "GpuHelpers.h"
|
#include "GpuHelpers.h"
|
||||||
|
#include "GLMHelpers.h"
|
||||||
|
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
class Mesh;
|
class Mesh;
|
||||||
|
@ -55,8 +56,8 @@ namespace buffer_helpers {
|
||||||
tangent = glm::clamp(tangent, -1.0f, 1.0f);
|
tangent = glm::clamp(tangent, -1.0f, 1.0f);
|
||||||
normal *= 511.0f;
|
normal *= 511.0f;
|
||||||
tangent *= 511.0f;
|
tangent *= 511.0f;
|
||||||
normal = glm::round(normal);
|
normal = fastRoundf(normal);
|
||||||
tangent = glm::round(tangent);
|
tangent = fastRoundf(tangent);
|
||||||
|
|
||||||
glm::detail::i10i10i10i2 normalStruct;
|
glm::detail::i10i10i10i2 normalStruct;
|
||||||
glm::detail::i10i10i10i2 tangentStruct;
|
glm::detail::i10i10i10i2 tangentStruct;
|
||||||
|
|
|
@ -79,33 +79,23 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& scale) {
|
||||||
|
|
||||||
glm::vec3 AABox::getFarthestVertex(const glm::vec3& normal) const {
|
glm::vec3 AABox::getFarthestVertex(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
if (normal.x > 0.0f) {
|
float blend = (float)(normal.x > 0.0f);
|
||||||
result.x += _scale.x;
|
result.x += blend * _scale.x + (1.0f - blend) * 0.0f;
|
||||||
}
|
blend = (float)(normal.y > 0.0f);
|
||||||
if (normal.y > 0.0f) {
|
result.y += blend * _scale.y + (1.0f - blend) * 0.0f;
|
||||||
result.y += _scale.y;
|
blend = (float)(normal.z > 0.0f);
|
||||||
}
|
result.z += blend * _scale.z + (1.0f - blend) * 0.0f;
|
||||||
if (normal.z > 0.0f) {
|
|
||||||
result.z += _scale.z;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AABox::getNearestVertex(const glm::vec3& normal) const {
|
glm::vec3 AABox::getNearestVertex(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
|
float blend = (float)(normal.x < 0.0f);
|
||||||
if (normal.x < 0.0f) {
|
result.x += blend * _scale.x + (1.0f - blend) * 0.0f;
|
||||||
result.x += _scale.x;
|
blend = (float)(normal.y < 0.0f);
|
||||||
}
|
result.y += blend * _scale.y + (1.0f - blend) * 0.0f;
|
||||||
|
blend = (float)(normal.z < 0.0f);
|
||||||
if (normal.y < 0.0f) {
|
result.z += blend * _scale.z + (1.0f - blend) * 0.0f;
|
||||||
result.y += _scale.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (normal.z < 0.0f) {
|
|
||||||
result.z += _scale.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,28 +449,6 @@ AABox AABox::clamp(float min, float max) const {
|
||||||
return AABox(clampedCorner, clampedScale);
|
return AABox(clampedCorner, clampedScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
AABox& AABox::operator += (const glm::vec3& point) {
|
|
||||||
|
|
||||||
if (isInvalid()) {
|
|
||||||
_corner = glm::min(_corner, point);
|
|
||||||
} else {
|
|
||||||
glm::vec3 maximum(_corner + _scale);
|
|
||||||
_corner = glm::min(_corner, point);
|
|
||||||
maximum = glm::max(maximum, point);
|
|
||||||
_scale = maximum - _corner;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
AABox& AABox::operator += (const AABox& box) {
|
|
||||||
if (!box.isInvalid()) {
|
|
||||||
(*this) += box._corner;
|
|
||||||
(*this) += box.calcTopFarLeft();
|
|
||||||
}
|
|
||||||
return (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AABox::embiggen(float scale) {
|
void AABox::embiggen(float scale) {
|
||||||
_corner += scale * (-0.5f * _scale);
|
_corner += scale * (-0.5f * _scale);
|
||||||
_scale *= scale;
|
_scale *= scale;
|
||||||
|
|
|
@ -85,8 +85,21 @@ public:
|
||||||
AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
|
AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
|
||||||
AABox clamp(float min, float max) const;
|
AABox clamp(float min, float max) const;
|
||||||
|
|
||||||
AABox& operator += (const glm::vec3& point);
|
inline AABox& operator+=(const glm::vec3& point) {
|
||||||
AABox& operator += (const AABox& box);
|
float blend = (float)isInvalid();
|
||||||
|
glm::vec3 maximumScale(glm::max(_scale, point - _corner));
|
||||||
|
_corner = glm::min(_corner, point);
|
||||||
|
_scale = blend * _scale + (1.0f - blend) * maximumScale;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AABox& operator+=(const AABox& box) {
|
||||||
|
if (!box.isInvalid()) {
|
||||||
|
(*this) += box._corner;
|
||||||
|
(*this) += box.calcTopFarLeft();
|
||||||
|
}
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
// Translate the AABox just moving the corner
|
// Translate the AABox just moving the corner
|
||||||
void translate(const glm::vec3& translation) { _corner += translation; }
|
void translate(const glm::vec3& translation) { _corner += translation; }
|
||||||
|
|
|
@ -316,4 +316,12 @@ inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline glm::vec3 fastRoundf(const glm::vec3& vec) {
|
||||||
|
#if GLM_ARCH & GLM_ARCH_SSE2_BIT
|
||||||
|
return glm::vec3(_mm_cvt_ss2si(_mm_set_ss(vec.x)), _mm_cvt_ss2si(_mm_set_ss(vec.y)), _mm_cvt_ss2si(_mm_set_ss(vec.z)));
|
||||||
|
#else
|
||||||
|
return glm::round(vec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif // hifi_GLMHelpers_h
|
#endif // hifi_GLMHelpers_h
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#define hifi_PrioritySortUtil_h
|
#define hifi_PrioritySortUtil_h
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include "NumericalConstants.h"
|
#include "NumericalConstants.h"
|
||||||
#include "shared/ConicalViewFrustum.h"
|
#include "shared/ConicalViewFrustum.h"
|
||||||
|
@ -75,7 +74,6 @@ namespace PrioritySortUtil {
|
||||||
|
|
||||||
void setPriority(float priority) { _priority = priority; }
|
void setPriority(float priority) { _priority = priority; }
|
||||||
float getPriority() const { return _priority; }
|
float getPriority() const { return _priority; }
|
||||||
bool operator<(const Sortable& other) const { return _priority < other._priority; }
|
|
||||||
private:
|
private:
|
||||||
float _priority { 0.0f };
|
float _priority { 0.0f };
|
||||||
};
|
};
|
||||||
|
@ -99,14 +97,15 @@ namespace PrioritySortUtil {
|
||||||
_usecCurrentTime = usecTimestampNow();
|
_usecCurrentTime = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return _queue.size(); }
|
size_t size() const { return _vector.size(); }
|
||||||
void push(T thing) {
|
void push(T thing) {
|
||||||
thing.setPriority(computePriority(thing));
|
thing.setPriority(computePriority(thing));
|
||||||
_queue.push(thing);
|
_vector.push_back(thing);
|
||||||
|
}
|
||||||
|
const std::vector<T>& getSortedVector() {
|
||||||
|
std::sort(_vector.begin(), _vector.end(), [](const T& left, const T& right) { return left.getPriority() > right.getPriority(); });
|
||||||
|
return _vector;
|
||||||
}
|
}
|
||||||
const T& top() const { return _queue.top(); }
|
|
||||||
void pop() { return _queue.pop(); }
|
|
||||||
bool empty() const { return _queue.empty(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -156,7 +155,7 @@ namespace PrioritySortUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
ConicalViewFrustums _views;
|
ConicalViewFrustums _views;
|
||||||
std::priority_queue<T> _queue;
|
std::vector<T> _vector;
|
||||||
float _angularWeight { DEFAULT_ANGULAR_COEF };
|
float _angularWeight { DEFAULT_ANGULAR_COEF };
|
||||||
float _centerWeight { DEFAULT_CENTER_COEF };
|
float _centerWeight { DEFAULT_CENTER_COEF };
|
||||||
float _ageWeight { DEFAULT_AGE_COEF };
|
float _ageWeight { DEFAULT_AGE_COEF };
|
||||||
|
|
|
@ -173,7 +173,7 @@ void AACubeTests::rayVsParabolaPerformance() {
|
||||||
glm::vec3 normal;
|
glm::vec3 normal;
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
for (auto& cube : cubes) {
|
for (auto& cube : cubes) {
|
||||||
if (cube.findRayIntersection(origin, direction, distance, face, normal)) {
|
if (cube.findRayIntersection(origin, direction, 1.0f / direction, distance, face, normal)) {
|
||||||
numRayHits++;
|
numRayHits++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,3 +214,39 @@ void GLMHelpersTests::testGenerateBasisVectors() {
|
||||||
QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON);
|
QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLMHelpersTests::roundPerf() {
|
||||||
|
const int NUM_VECS = 1000000;
|
||||||
|
const float MAX_VEC = 500.0f;
|
||||||
|
std::vector<glm::vec3> vecs;
|
||||||
|
vecs.reserve(NUM_VECS);
|
||||||
|
for (int i = 0; i < NUM_VECS; i++) {
|
||||||
|
vecs.emplace_back(randFloatInRange(-MAX_VEC, MAX_VEC), randFloatInRange(-MAX_VEC, MAX_VEC), randFloatInRange(-MAX_VEC, MAX_VEC));
|
||||||
|
}
|
||||||
|
std::vector<glm::vec3> vecs2 = vecs;
|
||||||
|
std::vector<glm::vec3> originalVecs = vecs;
|
||||||
|
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
for (auto& vec : vecs) {
|
||||||
|
vec = glm::round(vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto glmTime = std::chrono::high_resolution_clock::now() - start;
|
||||||
|
start = std::chrono::high_resolution_clock::now();
|
||||||
|
for (auto& vec : vecs2) {
|
||||||
|
vec = fastRoundf(vec);
|
||||||
|
}
|
||||||
|
auto manualTime = std::chrono::high_resolution_clock::now() - start;
|
||||||
|
|
||||||
|
bool identical = true;
|
||||||
|
for (int i = 0; i < vecs.size(); i++) {
|
||||||
|
identical &= vecs[i] == vecs2[i];
|
||||||
|
if (vecs[i] != vecs2[i]) {
|
||||||
|
qDebug() << "glm: " << vecs[i].x << vecs[i].y << vecs[i].z << ", manual: " << vecs2[i].x << vecs2[i].y << vecs2[i].z;
|
||||||
|
qDebug() << "original: " << originalVecs[i].x << originalVecs[i].y << originalVecs[i].z;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "ratio: " << (float)glmTime.count() / (float)manualTime.count() << ", identical: " << identical;
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ private slots:
|
||||||
void testSixByteOrientationCompression();
|
void testSixByteOrientationCompression();
|
||||||
void testSimd();
|
void testSimd();
|
||||||
void testGenerateBasisVectors();
|
void testGenerateBasisVectors();
|
||||||
|
void roundPerf();
|
||||||
};
|
};
|
||||||
|
|
||||||
float getErrorDifference(const float& a, const float& b);
|
float getErrorDifference(const float& a, const float& b);
|
||||||
|
|
Loading…
Reference in a new issue