Optimize View Frustum wire format.

- Changed View frstum orientaton to be a quaternion
- Implemented packing formats for Orientation Quats, Ratios, and Clipping values
- Changed wire format for View Frustum details to be more efficient 28 bytes vs 64 bytes
This commit is contained in:
ZappoMan 2013-05-27 09:56:35 -07:00
parent 77601c880c
commit 12dc11fbfa
10 changed files with 210 additions and 96 deletions

View file

@ -1092,7 +1092,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
void Application::addVoxelInFrontOfAvatar() {
VoxelDetail detail;
glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.getCameraDirection()) * (1.0f / TREE_SCALE);
glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.calculateCameraDirection()) * (1.0f / TREE_SCALE);
detail.s = _mouseVoxelScale;
detail.x = detail.s * floor(position.x / detail.s);
@ -1347,9 +1347,7 @@ void Application::updateAvatar(float deltaTime) {
// to the server.
loadViewFrustum(_myCamera, _viewFrustum);
_myAvatar.setCameraPosition(_viewFrustum.getPosition());
_myAvatar.setCameraDirection(_viewFrustum.getDirection());
_myAvatar.setCameraUp(_viewFrustum.getUp());
_myAvatar.setCameraRight(_viewFrustum.getRight());
_myAvatar.setCameraOrientation(_viewFrustum.getOrientation());
_myAvatar.setCameraFov(_viewFrustum.getFieldOfView());
_myAvatar.setCameraAspectRatio(_viewFrustum.getAspectRatio());
_myAvatar.setCameraNearClip(_viewFrustum.getNearClip());
@ -1435,7 +1433,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
// Set the viewFrustum up with the correct position and orientation of the camera
viewFrustum.setPosition(position);
viewFrustum.setOrientation(direction,up,right);
viewFrustum.setOrientation(o.getQuat());
// Also make sure it's got the correct lens details from the camera
viewFrustum.setFieldOfView(fov);

View file

@ -80,8 +80,8 @@ Avatar::Avatar(Agent* owningAgent) :
_bodyRollDelta(0.0f),
_movedHandOffset(0.0f, 0.0f, 0.0f),
_rotation(0.0f, 0.0f, 0.0f, 0.0f),
_cameraPosition(0.0f, 0.0f, 0.0f),
_mode(AVATAR_MODE_STANDING),
_cameraPosition(0.0f, 0.0f, 0.0f),
_handHoldingPosition(0.0f, 0.0f, 0.0f),
_velocity(0.0f, 0.0f, 0.0f),
_thrust(0.0f, 0.0f, 0.0f),

View file

@ -62,9 +62,9 @@ Head::Head(Avatar* owningAvatar) :
_audioAttack(0.0f),
_returnSpringScale(1.0f),
_bodyRotation(0.0f, 0.0f, 0.0f),
_renderLookatVectors(false),
_mohawkTriangleFan(NULL),
_mohawkColors(NULL),
_renderLookatVectors(false) {
_mohawkColors(NULL) {
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
_hairTuft[t].length = HAIR_LENGTH;

View file

@ -17,20 +17,6 @@
using namespace std;
int packFloatAngleToTwoByte(unsigned char* buffer, float angle) {
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);
uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO);
memcpy(buffer, &angleHolder, sizeof(uint16_t));
return sizeof(uint16_t);
}
int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer) {
*destinationPointer = (*byteAnglePointer / (float) std::numeric_limits<uint16_t>::max()) * 360.0 - 180;
return sizeof(uint16_t);
}
AvatarData::AvatarData(Agent* owningAgent) :
AgentData(owningAgent),
_handPosition(0,0,0),
@ -40,9 +26,7 @@ AvatarData::AvatarData(Agent* owningAgent) :
_audioLoudness(0),
_handState(0),
_cameraPosition(0,0,0),
_cameraDirection(0,0,0),
_cameraUp(0,0,0),
_cameraRight(0,0,0),
_cameraOrientation(),
_cameraFov(0.0f),
_cameraAspectRatio(0.0f),
_cameraNearClip(0.0f),
@ -110,20 +94,11 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
// camera details
memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition));
destinationBuffer += sizeof(_cameraPosition);
memcpy(destinationBuffer, &_cameraDirection, sizeof(_cameraDirection));
destinationBuffer += sizeof(_cameraDirection);
memcpy(destinationBuffer, &_cameraRight, sizeof(_cameraRight));
destinationBuffer += sizeof(_cameraRight);
memcpy(destinationBuffer, &_cameraUp, sizeof(_cameraUp));
destinationBuffer += sizeof(_cameraUp);
memcpy(destinationBuffer, &_cameraFov, sizeof(_cameraFov));
destinationBuffer += sizeof(_cameraFov);
memcpy(destinationBuffer, &_cameraAspectRatio, sizeof(_cameraAspectRatio));
destinationBuffer += sizeof(_cameraAspectRatio);
memcpy(destinationBuffer, &_cameraNearClip, sizeof(_cameraNearClip));
destinationBuffer += sizeof(_cameraNearClip);
memcpy(destinationBuffer, &_cameraFarClip, sizeof(_cameraFarClip));
destinationBuffer += sizeof(_cameraFarClip);
destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _cameraOrientation);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _cameraFov);
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _cameraAspectRatio);
destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraNearClip);
destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraFarClip);
// key state
*destinationBuffer++ = _keyState;
@ -204,20 +179,11 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// camera details
memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition));
sourceBuffer += sizeof(_cameraPosition);
memcpy(&_cameraDirection, sourceBuffer, sizeof(_cameraDirection));
sourceBuffer += sizeof(_cameraDirection);
memcpy(&_cameraRight, sourceBuffer, sizeof(_cameraRight));
sourceBuffer += sizeof(_cameraRight);
memcpy(&_cameraUp, sourceBuffer, sizeof(_cameraUp));
sourceBuffer += sizeof(_cameraUp);
memcpy(&_cameraFov, sourceBuffer, sizeof(_cameraFov));
sourceBuffer += sizeof(_cameraFov);
memcpy(&_cameraAspectRatio, sourceBuffer, sizeof(_cameraAspectRatio));
sourceBuffer += sizeof(_cameraAspectRatio);
memcpy(&_cameraNearClip, sourceBuffer, sizeof(_cameraNearClip));
sourceBuffer += sizeof(_cameraNearClip);
memcpy(&_cameraFarClip, sourceBuffer, sizeof(_cameraFarClip));
sourceBuffer += sizeof(_cameraFarClip);
sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _cameraOrientation);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_cameraFov);
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer,_cameraAspectRatio);
sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraNearClip);
sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraFarClip);
// key state
_keyState = (KeyState)*sourceBuffer++;
@ -236,3 +202,112 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
return sourceBuffer - startPosition;
}
glm::vec3 AvatarData::calculateCameraDirection() const {
const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f);
glm::mat4 rotationMatrix = glm::mat4_cast(_cameraOrientation);
glm::vec3 direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix);
return direction;
}
int packFloatAngleToTwoByte(unsigned char* buffer, float angle) {
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);
uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO);
memcpy(buffer, &angleHolder, sizeof(uint16_t));
return sizeof(uint16_t);
}
int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer) {
*destinationPointer = (*byteAnglePointer / (float) std::numeric_limits<uint16_t>::max()) * 360.0 - 180;
return sizeof(uint16_t);
}
int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) {
const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 2.0);
uint16_t quatParts[4];
quatParts[0] = floorf((quatInput.x + 1.0) * QUAT_PART_CONVERSION_RATIO);
quatParts[1] = floorf((quatInput.y + 1.0) * QUAT_PART_CONVERSION_RATIO);
quatParts[2] = floorf((quatInput.z + 1.0) * QUAT_PART_CONVERSION_RATIO);
quatParts[3] = floorf((quatInput.w + 1.0) * QUAT_PART_CONVERSION_RATIO);
memcpy(buffer, &quatParts, sizeof(quatParts));
return sizeof(quatParts);
}
int unpackOrientationQuatFromBytes(unsigned char* buffer, glm::quat& quatOutput) {
uint16_t quatParts[4];
memcpy(&quatParts, buffer, sizeof(quatParts));
quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.0) - 1.0;
quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.0) - 1.0;
quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.0) - 1.0;
quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.0) - 1.0;
return sizeof(quatParts);
}
float SMALL_LIMIT = 10.0;
float LARGE_LIMIT = 1000.0;
int packFloatRatioToTwoByte(unsigned char* buffer, float ratio) {
// if the ratio is less than 10, then encode it as a positive number scaled from 0 to int16::max()
int16_t ratioHolder;
if (ratio < SMALL_LIMIT) {
const float SMALL_RATIO_CONVERSION_RATIO = (std::numeric_limits<int16_t>::max() / SMALL_LIMIT);
ratioHolder = floorf(ratio * SMALL_RATIO_CONVERSION_RATIO);
} else {
const float LARGE_RATIO_CONVERSION_RATIO = std::numeric_limits<int16_t>::min() / LARGE_LIMIT;
ratioHolder = floorf((std::min(ratio,LARGE_LIMIT) - SMALL_LIMIT) * LARGE_RATIO_CONVERSION_RATIO);
}
memcpy(buffer, &ratioHolder, sizeof(ratioHolder));
return sizeof(ratioHolder);
}
int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio) {
int16_t ratioHolder;
memcpy(&ratioHolder, buffer, sizeof(ratioHolder));
// If it's positive, than the original ratio was less than SMALL_LIMIT
if (ratioHolder > 0) {
ratio = (ratioHolder / (float) std::numeric_limits<int16_t>::max()) * SMALL_LIMIT;
} else {
// If it's negative, than the original ratio was between SMALL_LIMIT and LARGE_LIMIT
ratio = ((ratioHolder / (float) std::numeric_limits<int16_t>::min()) * LARGE_LIMIT) + SMALL_LIMIT;
}
return sizeof(ratioHolder);
}
int packClipValueToTwoByte(unsigned char* buffer, float clipValue) {
// Clip values must be less than max signed 16bit integers
assert(clipValue < std::numeric_limits<int16_t>::max());
int16_t holder;
// if the clip is less than 10, then encode it as a positive number scaled from 0 to int16::max()
if (clipValue < SMALL_LIMIT) {
const float SMALL_RATIO_CONVERSION_RATIO = (std::numeric_limits<int16_t>::max() / SMALL_LIMIT);
holder = floorf(clipValue * SMALL_RATIO_CONVERSION_RATIO);
} else {
// otherwise we store it as a negative integer
holder = -1 * floorf(clipValue);
}
memcpy(buffer, &holder, sizeof(holder));
return sizeof(holder);
}
int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue) {
int16_t holder;
memcpy(&holder, buffer, sizeof(holder));
// If it's positive, than the original clipValue was less than SMALL_LIMIT
if (holder > 0) {
clipValue = (holder / (float) std::numeric_limits<int16_t>::max()) * SMALL_LIMIT;
} else {
// If it's negative, than the original holder can be found as the opposite sign of holder
clipValue = -1.0f * holder;
}
return sizeof(holder);
}

View file

@ -12,6 +12,7 @@
#include <string>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <AgentData.h>
#include "HeadData.h"
@ -58,19 +59,17 @@ public:
// getters for camera details
const glm::vec3& getCameraPosition() const { return _cameraPosition; };
const glm::vec3& getCameraDirection() const { return _cameraDirection; }
const glm::vec3& getCameraUp() const { return _cameraUp; }
const glm::vec3& getCameraRight() const { return _cameraRight; }
const glm::quat& getCameraOrientation() const { return _cameraOrientation; }
float getCameraFov() const { return _cameraFov; }
float getCameraAspectRatio() const { return _cameraAspectRatio; }
float getCameraNearClip() const { return _cameraNearClip; }
float getCameraFarClip() const { return _cameraFarClip; }
glm::vec3 calculateCameraDirection() const;
// setters for camera details
void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; };
void setCameraDirection(const glm::vec3& direction) { _cameraDirection = direction; }
void setCameraUp(const glm::vec3& up) { _cameraUp = up; }
void setCameraRight(const glm::vec3& right) { _cameraRight = right; }
void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; }
void setCameraOrientation(const glm::quat& orientation) { _cameraOrientation = orientation; }
void setCameraFov(float fov) { _cameraFov = fov; }
void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; }
void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; }
@ -111,11 +110,7 @@ protected:
// camera details for the avatar
glm::vec3 _cameraPosition;
// can we describe this in less space? For example, a Quaternion? or Euler angles?
glm::vec3 _cameraDirection;
glm::vec3 _cameraUp;
glm::vec3 _cameraRight;
glm::quat _cameraOrientation;
float _cameraFov;
float _cameraAspectRatio;
float _cameraNearClip;
@ -139,4 +134,27 @@ private:
AvatarData& operator= (const AvatarData&);
};
// These pack/unpack functions are designed to start specific known types in as efficient a manner
// as possible. Taking advantage of the known characteristics of the semantic types.
// Angles are known to be between 0 and 360deg, this allows us to encode in 16bits with great accuracy
int packFloatAngleToTwoByte(unsigned char* buffer, float angle);
int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer);
// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0
// this allows us to encode each component in 16bits with great accuracy
int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput);
int unpackOrientationQuatFromBytes(unsigned char* buffer, glm::quat& quatOutput);
// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they
// are never greater than 1000 to 1, this allows us to encode each component in 16bits
int packFloatRatioToTwoByte(unsigned char* buffer, float ratio);
int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio);
// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and
// they are never greater than 16,000, this allows us to encode each component in 16bits
int packClipValueToTwoByte(unsigned char* buffer, float clipValue);
int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue);
#endif /* defined(__hifi__AvatarData__) */

View file

@ -421,3 +421,4 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex,
}
return -1; // error case
}

View file

@ -87,4 +87,5 @@ class debug {
public:
static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; };
};
#endif /* defined(__hifi__SharedUtil__) */

View file

@ -19,22 +19,40 @@
using namespace std;
ViewFrustum::ViewFrustum() :
_position(glm::vec3(0,0,0)),
_direction(glm::vec3(0,0,0)),
_up(glm::vec3(0,0,0)),
_right(glm::vec3(0,0,0)),
_position(0,0,0),
_orientation(),
_direction(0,0,0),
_up(0,0,0),
_right(0,0,0),
_fieldOfView(0.0),
_aspectRatio(1.0),
_nearClip(0.1),
_farClip(500.0),
_farTopLeft(glm::vec3(0,0,0)),
_farTopRight(glm::vec3(0,0,0)),
_farBottomLeft(glm::vec3(0,0,0)),
_farBottomRight(glm::vec3(0,0,0)),
_nearTopLeft(glm::vec3(0,0,0)),
_nearTopRight(glm::vec3(0,0,0)),
_nearBottomLeft(glm::vec3(0,0,0)),
_nearBottomRight(glm::vec3(0,0,0)) { }
_farTopLeft(0,0,0),
_farTopRight(0,0,0),
_farBottomLeft(0,0,0),
_farBottomRight(0,0,0),
_nearTopLeft(0,0,0),
_nearTopRight(0,0,0),
_nearBottomLeft(0,0,0),
_nearBottomRight(0,0,0) { }
void ViewFrustum::setOrientation(const glm::quat& orientationAsQuaternion) {
glm::quat quat;
quat = quat * orientationAsQuaternion;
// this is where the coordinate system is represented
const glm::vec3 IDENTITY_RIGHT = glm::vec3(-1.0f, 0.0f, 0.0f);
const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f);
const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f);
glm::mat4 rotationMatrix = glm::mat4_cast(quat);
_orientation = orientationAsQuaternion;
_right = glm::vec3(glm::vec4(IDENTITY_RIGHT, 0.0f) * rotationMatrix);
_up = glm::vec3(glm::vec4(IDENTITY_UP, 0.0f) * rotationMatrix);
_direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix);
}
/////////////////////////////////////////////////////////////////////////////////////
// ViewFrustum::calculateViewFrustum()

View file

@ -21,6 +21,9 @@ private:
// camera location/orientation attributes
glm::vec3 _position;
glm::quat _orientation;
// calculated for orientation
glm::vec3 _direction;
glm::vec3 _up;
glm::vec3 _right;
@ -53,23 +56,23 @@ private:
public:
// setters for camera attributes
void setPosition (const glm::vec3& p) { _position = p; }
void setOrientation (const glm::vec3& d, const glm::vec3& u, const glm::vec3& r )
{ _direction = d; _up = u; _right = r; }
void setPosition (const glm::vec3& p) { _position = p; };
void setOrientation (const glm::quat& orientationAsQuaternion);
// getters for camera attributes
const glm::vec3& getPosition() const { return _position; };
const glm::quat& getOrientation() const { return _orientation; };
const glm::vec3& getDirection() const { return _direction; };
const glm::vec3& getUp() const { return _up; };
const glm::vec3& getRight() const { return _right; };
// setters for lens attributes
void setFieldOfView ( float f ) { _fieldOfView = f; }
void setAspectRatio ( float a ) { _aspectRatio = a; }
void setNearClip ( float n ) { _nearClip = n; }
void setFarClip ( float f ) { _farClip = f; }
void setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; }
void setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; }
void setFieldOfView ( float f ) { _fieldOfView = f; };
void setAspectRatio ( float a ) { _aspectRatio = a; };
void setNearClip ( float n ) { _nearClip = n; };
void setFarClip ( float f ) { _farClip = f; };
void setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; };
void setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; };
// getters for lens attributes

View file

@ -50,7 +50,7 @@ bool VoxelAgentData::updateCurrentViewFrustum() {
ViewFrustum newestViewFrustum;
// get position and orientation details from the camera
newestViewFrustum.setPosition(getCameraPosition());
newestViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight());
newestViewFrustum.setOrientation(getCameraOrientation());
// Also make sure it's got the correct lens details from the camera
newestViewFrustum.setFieldOfView(getCameraFov());