Merge branch 'master' of github.com:worklist/hifi into pairing

This commit is contained in:
Stephen Birarda 2013-05-02 13:33:21 -07:00
commit c2f6d3b8f9
18 changed files with 742 additions and 697 deletions

View file

@ -113,7 +113,8 @@ int main(int argc, const char* argv[]) {
// move eve away from the origin
// pick a random point inside a 10x10 grid
eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION), 0.4,
eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION),
0.32, // this is the same as the pelvis standing height (as of 4/26/13)
randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION)));
// face any instance of eve down the z-axis
@ -121,7 +122,7 @@ int main(int argc, const char* argv[]) {
// put her hand out so somebody can shake it
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
0.32, // this is the same as the pelvis standing height (as of 4/26/13)
0.25,
eve.getPosition()[2] + 0.1));
// read eve's audio data
AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw");

View file

@ -4,7 +4,7 @@
//
// Created by Philip Rosedale on 9/11/12.
// adapted by Jeffrey Ventrella
// Copyright (c) 2012 Physical, Inc.. All rights reserved.
// Copyright (c) 2013 Physical, Inc.. All rights reserved.
//
#include <glm/glm.hpp>
@ -20,11 +20,15 @@
using namespace std;
/*
const bool BALLS_ON = false;
const bool AVATAR_GRAVITY = true;
const float DECAY = 0.1;
const float THRUST_MAG = 1200.0;
//const float THRUST_MAG = 1200.0;
const float THRUST_MAG = 0.0;
const float YAW_MAG = 500.0; //JJV - changed from 300.0;
const float TEST_YAW_DECAY = 5.0;
const float LIN_VEL_DECAY = 5.0;
@ -32,17 +36,13 @@ const float MY_HAND_HOLDING_PULL = 0.2;
const float YOUR_HAND_HOLDING_PULL = 1.0;
const float BODY_SPRING_FORCE = 6.0f;
const float BODY_SPRING_DECAY = 16.0f;
//const float COLLISION_FRICTION = 0.5;
//const float COLLISION_RADIUS_SCALAR = 1.8;
//const float COLLISION_BALL_FORCE = 0.1;
//const float COLLISION_BODY_FORCE = 3.0;
const float COLLISION_RADIUS_SCALAR = 1.8;
const float COLLISION_BALL_FORCE = 0.6;
const float COLLISION_BODY_FORCE = 6.0;
const float COLLISION_BALL_FRICTION = 200.0;
const float COLLISION_BODY_FRICTION = 0.5;
*/
float skinColor[] = {1.0, 0.84, 0.66};
float lightBlue[] = { 0.7, 0.8, 1.0 };
float browColor[] = {210.0/255.0, 105.0/255.0, 30.0/255.0};
@ -78,7 +78,9 @@ Avatar::Avatar(bool isMine) {
_bodyYaw = -90.0;
_bodyPitch = 0.0;
_bodyRoll = 0.0;
_bodyPitchDelta = 0.0;
_bodyYawDelta = 0.0;
_bodyRollDelta = 0.0;
_mousePressed = false;
_mode = AVATAR_MODE_STANDING;
_isMine = isMine;
@ -138,9 +140,9 @@ Avatar::Avatar(bool isMine) {
_renderPitch = 0.0;
_sphere = NULL;
_interactingOther = NULL;
_interactingOtherIsNearby = false;
//_canReachToOtherAvatar = false;
_handHoldingPosition = glm::vec3( 0.0, 0.0, 0.0 );
initializeSkeleton();
if (iris_texture.size() == 0) {
@ -155,17 +157,18 @@ Avatar::Avatar(bool isMine) {
else { _balls = NULL; }
}
Avatar::Avatar(const Avatar &otherAvatar) {
_velocity = otherAvatar._velocity;
_thrust = otherAvatar._thrust;
_rotation = otherAvatar._rotation;
_interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby;
//_canReachToOtherAvatar = otherAvatar._canReachToOtherAvatar;
_bodyYaw = otherAvatar._bodyYaw;
_bodyPitch = otherAvatar._bodyPitch;
_bodyRoll = otherAvatar._bodyRoll;
_bodyPitchDelta = otherAvatar._bodyPitchDelta;
_bodyYawDelta = otherAvatar._bodyYawDelta;
_bodyRollDelta = otherAvatar._bodyRollDelta;
_mousePressed = otherAvatar._mousePressed;
_mode = otherAvatar._mode;
_isMine = otherAvatar._isMine;
@ -182,6 +185,7 @@ Avatar::Avatar(const Avatar &otherAvatar) {
_TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition;
_movedHandOffset = otherAvatar._movedHandOffset;
_usingBodySprings = otherAvatar._usingBodySprings;
_orientation.set( otherAvatar._orientation );
_sphere = NULL;
@ -227,7 +231,6 @@ Avatar::Avatar(const Avatar &otherAvatar) {
_head.browAudioLift = otherAvatar._head.browAudioLift;
_head.noise = otherAvatar._head.noise;
initializeSkeleton();
if (iris_texture.size() == 0) {
@ -318,8 +321,22 @@ void Avatar::setMousePressed( bool d ) {
}
bool Avatar::getIsNearInteractingOther() {
return _avatarTouch.getAbleToReachOtherAvatar();
}
void Avatar::simulate(float deltaTime) {
//keep this - I'm still using it to test things....
/*
//TEST
static float tt = 0.0f;
tt += deltaTime * 2.0f;
//_head.leanSideways = 0.01 * sin( tt );
_head.leanForward = 0.02 * sin( tt * 0.8 );
*/
// update balls
if (_balls) { _balls->simulate(deltaTime); }
@ -329,19 +346,19 @@ void Avatar::simulate(float deltaTime) {
// reset hand and arm positions according to hand movement
updateHandMovement( deltaTime );
if ( !_interactingOtherIsNearby ) {
if ( !_avatarTouch.getAbleToReachOtherAvatar() ) {
//initialize _handHolding
_handHoldingPosition = _bone[ AVATAR_BONE_RIGHT_HAND ].position;
}
_interactingOtherIsNearby = false;
//reset these for the next go-round
_avatarTouch.setAbleToReachOtherAvatar (false);
_avatarTouch.setHandsCloseEnoughToGrasp(false);
// if the avatar being simulated is mine, then loop through
// all the other avatars for potential interactions...
if ( _isMine )
{
float closestDistance = 10000.0f;
AgentList* agentList = AgentList::getInstance();
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
@ -352,25 +369,42 @@ void Avatar::simulate(float deltaTime) {
// test other avatar hand position for proximity
glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position );
v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND );
v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_SHOULDER );
float distance = glm::length( v );
if ( distance < _maxArmLength + _maxArmLength ) {
closestDistance = distance;
_interactingOther = otherAvatar;
_interactingOtherIsNearby = true;
_avatarTouch.setAbleToReachOtherAvatar(true);
glm::vec3 vectorBetweenHands( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
vectorBetweenHands -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND );
float distanceBetweenHands = glm::length(vectorBetweenHands);
if (distanceBetweenHands < _avatarTouch.HANDS_CLOSE_ENOUGH_TO_GRASP) {
_avatarTouch.setHandsCloseEnoughToGrasp(true);
}
// if I am holding hands with another avatar, a force is applied
if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) {
glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition;
glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHoldingPosition;
_handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL;
_handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL;
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHoldingPosition;
// if the hands are close enough to grasp...
if (distanceBetweenHands < _avatarTouch.HANDS_CLOSE_ENOUGH_TO_GRASP)
{
// apply the forces...
glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition;
glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHoldingPosition;
_handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL;
_handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL;
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHoldingPosition;
// apply a force to the avatar body
if ( glm::length(vectorToOtherHand) > _maxArmLength * 0.9 ) {
_velocity += vectorToOtherHand;
}
}
}
_avatarTouch.setYourHandPosition( _interactingOther->_handPosition );
}
}
}
@ -378,19 +412,23 @@ void Avatar::simulate(float deltaTime) {
// Set the vector we send for hand position to other people to be our right hand
setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position);
//update the effects of touching another avatar
_avatarTouch.simulate(deltaTime);
}//if ( _isMine )
//constrain right arm length and re-adjust elbow position as it bends
updateArmIKAndConstraints( deltaTime );
if (_isMine) {
_avatarTouch.setMyHandPosition( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
// set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints
if ( _interactingOther ) {
if (_isMine) {
_avatarTouch.setMyHandPosition ( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
_avatarTouch.setYourHandPosition( _interactingOther->_bone[ AVATAR_BONE_RIGHT_HAND ].position );
_avatarTouch.setMyHandState ( _handState );
_avatarTouch.setYourHandState ( _interactingOther->_handState );
_avatarTouch.simulate(deltaTime);
}
}
if (!_interactingOtherIsNearby) {
if (!_avatarTouch.getAbleToReachOtherAvatar() ) {
_interactingOther = NULL;
}
@ -431,8 +469,10 @@ void Avatar::simulate(float deltaTime) {
_bodyYaw += _bodyYawDelta * deltaTime;
}
// decay body yaw delta
_bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime);
// decay body rotation deltas
_bodyPitchDelta *= (1.0 - BODY_PITCH_DECAY * deltaTime);
_bodyYawDelta *= (1.0 - BODY_YAW_DECAY * deltaTime);
_bodyRollDelta *= (1.0 - BODY_ROLL_DECAY * deltaTime);
// add thrust to velocity
_velocity += _thrust * deltaTime;
@ -457,11 +497,16 @@ void Avatar::simulate(float deltaTime) {
}
}
void Avatar::updateHead(float deltaTime) {
//apply the head lean values to the springy position...
if ( fabs( _head.leanSideways + _head.leanForward ) > 0.0f ) {
glm::vec3 headLean =
_orientation.getRight() * _head.leanSideways +
_orientation.getFront() * _head.leanForward;
_bone[ AVATAR_BONE_HEAD ].springyPosition += headLean;
}
// Decay head back to center if turned on
if (_returnHeadToCenter) {
// Decay back toward center
@ -477,10 +522,9 @@ void Avatar::updateHead(float deltaTime) {
_headRoll *= 1.f - (DECAY * deltaTime);
}
_head.leanForward *= (1.f - DECAY * 30 * deltaTime);
_head.leanSideways *= (1.f - DECAY * 30 * deltaTime);
// Update where the avatar's eyes are
//
// First, decide if we are making eye contact or not
@ -520,7 +564,6 @@ void Avatar::updateHead(float deltaTime) {
_head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust;
_head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust;
}
if (_head.noise)
{
@ -635,18 +678,16 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi
// push balls away from each other and apply friction
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime;
float ballMomentum = COLLISION_BALL_FRICTION * deltaTime;
float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime;
if ( ballMomentum < 0.0 ) { ballMomentum = 0.0;}
_bone[b].springyVelocity += ballPushForce;
otherAvatar->_bone[o].springyVelocity -= ballPushForce;
_bone[b].springyVelocity *= 0.9;
otherAvatar->_bone[o].springyVelocity *= 0.9;
_bone[b].springyVelocity *= ballMomentum;
otherAvatar->_bone[o].springyVelocity *= ballMomentum;
// accumulate forces and frictions to the velocities of avatar bodies
// accumulate forces and frictions to apply to the velocities of avatar bodies
bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime;
bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime;
if ( bodyMomentum < 0.0 ) { bodyMomentum = 0.0;}
@ -669,8 +710,6 @@ void Avatar::updateCollisionWithOtherAvatar( Avatar * otherAvatar, float deltaTi
} //method
void Avatar::setDisplayingHead( bool displayingHead ) {
_displayingHead = displayingHead;
}
@ -694,7 +733,6 @@ void Avatar::render(bool lookingInMirror) {
*/
if ( usingBigSphereCollisionTest ) {
// show TEST big sphere
glColor4f( 0.5f, 0.6f, 0.8f, 0.7 );
glPushMatrix();
@ -704,7 +742,7 @@ void Avatar::render(bool lookingInMirror) {
glPopMatrix();
}
// render body
//render body
renderBody();
// render head
@ -713,15 +751,11 @@ void Avatar::render(bool lookingInMirror) {
}
// if this is my avatar, then render my interactions with the other avatar
if ( _isMine )
{
if ( _interactingOtherIsNearby ) {
_avatarTouch.render();
}
if ( _isMine ) {
_avatarTouch.render();
}
// Render the balls
if (_balls) {
glPushMatrix();
glTranslatef(_position.x, _position.y, _position.z);
@ -778,7 +812,7 @@ void Avatar::renderHead(bool lookingInMirror) {
glEnable(GL_RESCALE_NORMAL);
// show head orientation
//renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f );
//renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].springyPosition, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f );
glPushMatrix();
@ -796,13 +830,13 @@ void Avatar::renderHead(bool lookingInMirror) {
glScalef( 0.03, 0.03, 0.03 );
if (lookingInMirror) {
glRotatef(_bodyYaw - _headYaw, 0, 1, 0);
glRotatef(_bodyYaw - _headYaw, 0, 1, 0);
glRotatef(_bodyPitch + _headPitch, 1, 0, 0);
glRotatef(_bodyRoll - _headRoll, 0, 0, 1);
glRotatef(_bodyRoll - _headRoll, 0, 0, 1);
} else {
glRotatef(_bodyYaw + _headYaw, 0, 1, 0);
glRotatef(_bodyYaw + _headYaw, 0, 1, 0);
glRotatef(_bodyPitch + _headPitch, 1, 0, 0);
glRotatef(_bodyRoll + _headRoll, 0, 0, 1);
glRotatef(_bodyRoll + _headRoll, 0, 0, 1);
}
glScalef(2.0, 2.0, 2.0);
@ -851,9 +885,7 @@ void Avatar::renderHead(bool lookingInMirror) {
}
glPopMatrix();
// Mouth
glPushMatrix();
glTranslatef(0,-0.35,0.75);
glColor3f(0,0,0);
@ -956,7 +988,7 @@ void Avatar::initializeSkeleton() {
_bone[b].roll = 0.0;
_bone[b].length = 0.0;
_bone[b].radius = 0.0;
_bone[b].springBodyTightness = 4.0;
_bone[b].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[b].orientation.setToIdentity();
}
@ -1034,7 +1066,35 @@ void Avatar::initializeSkeleton() {
_bone[ AVATAR_BONE_RIGHT_THIGH ].radius = 0.02;
_bone[ AVATAR_BONE_RIGHT_SHIN ].radius = 0.015;
_bone[ AVATAR_BONE_RIGHT_FOOT ].radius = 0.02;
// specify the tightness of the springy positions as far as attraction to rigid body
_bone[ AVATAR_BONE_PELVIS_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0;
_bone[ AVATAR_BONE_MID_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.8;
_bone[ AVATAR_BONE_CHEST_SPINE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_NECK ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.4;
_bone[ AVATAR_BONE_HEAD ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
_bone[ AVATAR_BONE_LEFT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_LEFT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_LEFT_UPPER_ARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_LEFT_FOREARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
_bone[ AVATAR_BONE_LEFT_HAND ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
_bone[ AVATAR_BONE_RIGHT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_RIGHT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
_bone[ AVATAR_BONE_RIGHT_FOREARM ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
_bone[ AVATAR_BONE_RIGHT_HAND ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
_bone[ AVATAR_BONE_LEFT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_LEFT_THIGH ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_LEFT_SHIN ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_LEFT_FOOT ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_RIGHT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_RIGHT_THIGH ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_RIGHT_SHIN ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
_bone[ AVATAR_BONE_RIGHT_FOOT ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
// to aid in hand-shaking and hand-holding, the right hand is not collidable
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].isCollidable = false;
_bone[ AVATAR_BONE_RIGHT_FOREARM ].isCollidable = false;
@ -1096,7 +1156,7 @@ void Avatar::updateSkeleton() {
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handPosition;
}
// the following will be replaced by a proper rotation...
// the following will be replaced by a proper rotation...close
float xx = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getRight() );
float yy = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getUp () );
float zz = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getFront() );
@ -1160,20 +1220,22 @@ void Avatar::updateBodySprings( float deltaTime ) {
const glm::vec3& Avatar::getHeadPosition() const {
if (_usingBodySprings) {
return _bone[ AVATAR_BONE_HEAD ].springyPosition;
}
//if (_usingBodySprings) {
// return _bone[ AVATAR_BONE_HEAD ].springyPosition;
//}
return _bone[ AVATAR_BONE_HEAD ].position;
}
void Avatar::updateHandMovement( float deltaTime ) {
glm::vec3 transformedHandMovement;
transformedHandMovement
= _orientation.getRight() * _movedHandOffset.x
+ _orientation.getUp() * -_movedHandOffset.y * 0.5f
+ _orientation.getFront() * -_movedHandOffset.y;
= _orientation.getRight() * _movedHandOffset.x * 2.0f
+ _orientation.getUp() * -_movedHandOffset.y * 1.0f
+ _orientation.getFront() * -_movedHandOffset.y * 1.0f;
_bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement;
@ -1207,7 +1269,9 @@ void Avatar::updateArmIKAndConstraints( float deltaTime ) {
// set elbow position
glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position;
newElbowPosition += armVector * ONE_HALF;
glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector );
newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF;
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition;
@ -1277,6 +1341,7 @@ void Avatar::renderBody() {
}
}
/*
// if the hand is grasping, show it...
if (( _usingBodySprings ) && ( _handState == 1 )) {
glPushMatrix();
@ -1289,6 +1354,7 @@ void Avatar::renderBody() {
glPopMatrix();
}
*/
}
void Avatar::SetNewHeadTarget(float pitch, float yaw) {

View file

@ -72,7 +72,6 @@ enum AvatarBoneID
NUM_AVATAR_BONES
};
class Avatar : public AvatarData {
public:
Avatar(bool isMine);
@ -93,8 +92,8 @@ public:
float getBodyYaw() {return _bodyYaw;};
void addBodyYaw(float y) {_bodyYaw += y;};
bool getIsNearInteractingOther() { return _interactingOtherIsNearby; }
bool getIsNearInteractingOther();
float getAbsoluteHeadYaw() const;
void setLeanForward(float dist);
void setLeanSideways(float dist);
@ -123,7 +122,7 @@ public:
void setDisplayingHead( bool displayingHead );
float getAverageLoudness() {return _head.averageLoudness;};
void setAverageLoudness(float al) {_head.averageLoudness = al;};
void setAverageLoudness(float al) {_head.averageLoudness = al;};
void SetNewHeadTarget(float, float);
@ -143,12 +142,32 @@ public:
// Find out what the local gravity vector is at this location
glm::vec3 getGravity(glm::vec3 pos);
private:
const bool BALLS_ON = false;
const bool AVATAR_GRAVITY = true;
const float DECAY = 0.1;
const float THRUST_MAG = 1200.0;
const float YAW_MAG = 500.0;
const float BODY_PITCH_DECAY = 5.0;
const float BODY_YAW_DECAY = 5.0;
const float BODY_ROLL_DECAY = 5.0;
const float LIN_VEL_DECAY = 5.0;
const float MY_HAND_HOLDING_PULL = 0.2;
const float YOUR_HAND_HOLDING_PULL = 1.0;
const float BODY_SPRING_FORCE = 6.0f;
const float BODY_SPRING_DECAY = 16.0f;
const float BODY_SPRING_DEFAULT_TIGHTNESS = 10.0f;
const float COLLISION_RADIUS_SCALAR = 1.8;
const float COLLISION_BALL_FORCE = 1.0;
const float COLLISION_BODY_FORCE = 6.0;
const float COLLISION_BALL_FRICTION = 60.0;
const float COLLISION_BODY_FRICTION = 0.5;
// Do you want head to try to return to center (depends on interface detected)
void setHeadReturnToCenter(bool r) { _returnHeadToCenter = r; };
const bool getHeadReturnToCenter() const { return _returnHeadToCenter; };
private:
struct AvatarBone
{
AvatarBoneID parent; // which bone is this bone connected to?
@ -208,42 +227,43 @@ private:
float returnSpringScale;
};
AvatarHead _head;
bool _isMine;
glm::vec3 _TEST_bigSpherePosition;
float _TEST_bigSphereRadius;
bool _mousePressed;
float _bodyYawDelta;
bool _usingBodySprings;
glm::vec3 _movedHandOffset;
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
AvatarBone _bone[ NUM_AVATAR_BONES ];
AvatarMode _mode;
glm::vec3 _handHoldingPosition;
glm::vec3 _velocity;
glm::vec3 _thrust;
float _speed;
float _maxArmLength;
Orientation _orientation;
int _driveKeys[MAX_DRIVE_KEYS];
GLUquadric* _sphere;
float _renderYaw;
float _renderPitch; // Pitch from view frustum when this is own head
bool _transmitterIsFirstData;
timeval _transmitterTimeLastReceived;
timeval _transmitterTimer;
float _transmitterHz;
int _transmitterPackets;
glm::vec3 _transmitterInitialReading;
Avatar* _interactingOther;
bool _interactingOtherIsNearby;
float _pelvisStandingHeight;
float _height;
Balls* _balls;
AvatarTouch _avatarTouch;
bool _displayingHead; // should be false if in first-person view
bool _returnHeadToCenter;
AvatarHead _head;
bool _isMine;
glm::vec3 _TEST_bigSpherePosition;
float _TEST_bigSphereRadius;
bool _mousePressed;
float _bodyPitchDelta;
float _bodyYawDelta;
float _bodyRollDelta;
bool _usingBodySprings;
glm::vec3 _movedHandOffset;
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
AvatarBone _bone[ NUM_AVATAR_BONES ];
AvatarMode _mode;
glm::vec3 _handHoldingPosition;
glm::vec3 _velocity;
glm::vec3 _thrust;
float _speed;
float _maxArmLength;
Orientation _orientation;
int _driveKeys[MAX_DRIVE_KEYS];
GLUquadric* _sphere;
float _renderYaw;
float _renderPitch; // Pitch from view frustum when this is own head
bool _transmitterIsFirstData;
timeval _transmitterTimeLastReceived;
timeval _transmitterTimer;
float _transmitterHz;
int _transmitterPackets;
glm::vec3 _transmitterInitialReading;
Avatar* _interactingOther;
float _pelvisStandingHeight;
float _height;
Balls* _balls;
AvatarTouch _avatarTouch;
bool _displayingHead; // should be false if in first-person view
bool _returnHeadToCenter;
// private methods...
void initializeSkeleton();
void updateSkeleton();

View file

@ -11,13 +11,18 @@
#include "AvatarTouch.h"
#include "InterfaceConfig.h"
const float THREAD_RADIUS = 0.007;
const float THREAD_RADIUS = 0.012;
AvatarTouch::AvatarTouch() {
_myHandPosition = glm::vec3( 0.0f, 0.0f, 0.0f );
_yourHandPosition = glm::vec3( 0.0f, 0.0f, 0.0f );
_myHandState = 0;
_yourHandState = 0;
_canReachToOtherAvatar = false;
_handsCloseEnoughToGrasp = false;
for (int p=0; p<NUM_POINTS; p++) {
_point[p] = glm::vec3( 0.0, 0.0, 0.0 );
}
@ -31,27 +36,61 @@ void AvatarTouch::setYourHandPosition( glm::vec3 position ) {
_yourHandPosition = position;
}
void AvatarTouch::setMyHandState( int state ) {
_myHandState = state;
}
void AvatarTouch::setYourHandState( int state ) {
_yourHandState = state;
}
void AvatarTouch::render() {
glm::vec3 v1( _myHandPosition );
glm::vec3 v2( _yourHandPosition );
if (_canReachToOtherAvatar) {
// if my hand is grasping, show it...
if ( _myHandState == 1 ) {
glPushMatrix();
glTranslatef(_myHandPosition.x, _myHandPosition.y, _myHandPosition.z);
glColor4f( 1.0, 1.0, 0.8, 0.3 ); glutSolidSphere( 0.020f, 10.0f, 10.0f );
glColor4f( 1.0, 1.0, 0.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
glPopMatrix();
}
// if your hand is grasping, show it...
if ( _yourHandState == 1 ) {
glPushMatrix();
glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z);
glColor4f( 1.0, 1.0, 0.8, 0.3 ); glutSolidSphere( 0.020f, 10.0f, 10.0f );
glColor4f( 1.0, 1.0, 0.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
glPopMatrix();
}
}
glLineWidth( 2.0 );
glColor4f( 0.7f, 0.4f, 0.1f, 0.3 );
glBegin( GL_LINE_STRIP );
glVertex3f( v1.x, v1.y, v1.z );
glVertex3f( v2.x, v2.y, v2.z );
glEnd();
glColor4f( 1.0f, 1.0f, 0.0f, 0.8 );
for (int p=0; p<NUM_POINTS; p++) {
glBegin(GL_POINTS);
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
//show beam
if (_handsCloseEnoughToGrasp) {
glLineWidth( 2.0 );
glColor4f( 0.7f, 0.4f, 0.1f, 0.3 );
glBegin( GL_LINE_STRIP );
glVertex3f( v1.x, v1.y, v1.z );
glVertex3f( v2.x, v2.y, v2.z );
glEnd();
}
glColor4f( 1.0f, 1.0f, 0.0f, 0.8 );
for (int p=0; p<NUM_POINTS; p++) {
glBegin(GL_POINTS);
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
glEnd();
}
}
}
void AvatarTouch::simulate (float deltaTime) {
glm::vec3 v = _yourHandPosition - _myHandPosition;

View file

@ -3,7 +3,7 @@
// interface
//
// Created by Jeffrey Ventrella
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__AvatarTouch__
@ -13,13 +13,25 @@
class AvatarTouch {
public:
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.1;
AvatarTouch();
void setMyHandPosition ( glm::vec3 position );
void setYourHandPosition( glm::vec3 position );
void simulate(float deltaTime);
void render();
void setMyHandPosition ( glm::vec3 position );
void setYourHandPosition( glm::vec3 position );
void setMyHandState ( int state );
void setYourHandState ( int state );
void setAbleToReachOtherAvatar ( bool a ) { _canReachToOtherAvatar = a; }
void setHandsCloseEnoughToGrasp( bool h ) { _handsCloseEnoughToGrasp = h; }
bool getAbleToReachOtherAvatar () { return _canReachToOtherAvatar; }
bool getHandsCloseEnoughToGrasp() { return _handsCloseEnoughToGrasp; }
private:
static const int NUM_POINTS = 100;
@ -27,6 +39,10 @@ private:
glm::vec3 _point [NUM_POINTS];
glm::vec3 _myHandPosition;
glm::vec3 _yourHandPosition;
int _myHandState;
int _yourHandState;
bool _canReachToOtherAvatar;
bool _handsCloseEnoughToGrasp;
};
#endif

View file

@ -34,12 +34,6 @@ Camera::Camera() {
void Camera::update( float deltaTime ) {
// generate the ortho-normals for the orientation based on the Euler angles
_orientation.setToIdentity();
_orientation.yaw ( _yaw );
_orientation.pitch( _pitch );
_orientation.roll ( _roll );
if ( _mode == CAMERA_MODE_NULL ) {
_modeShift = 0.0;
} else {
@ -53,6 +47,19 @@ void Camera::update( float deltaTime ) {
}
}
}
// do this AFTER making any changes to yaw pitch and roll....
generateOrientation();
}
// generate the ortho-normals for the orientation based on the three Euler angles
void Camera::generateOrientation() {
_orientation.setToIdentity();
_orientation.pitch( _pitch );
_orientation.yaw ( _yaw );
_orientation.roll ( _roll );
}
@ -71,9 +78,8 @@ void Camera::updateFollowMode( float deltaTime ) {
float radian = (_yaw / 180.0) * PIE;
// update _position
//these need to be checked to make sure they correspond to the correct coordinate system.
double x = _distance * -sin(radian);
double z = _distance * cos(radian);
double x = -_distance * sin(radian);
double z = -_distance * cos(radian);
double y = _upShift;
_idealPosition = _targetPosition + glm::vec3(x, y, z);

View file

@ -38,7 +38,6 @@ public:
void setTargetPosition( glm::vec3 t ) { _targetPosition = t; }
void setTargetYaw ( float y ) { _idealYaw = y; }
void setPosition ( glm::vec3 p ) { _position = p; }
void setOrientation ( Orientation o ) { _orientation.set(o); }
void setTightness ( float t ) { _tightness = t; }
void setMode ( CameraMode m );
@ -83,6 +82,7 @@ private:
float _tightness;
Orientation _orientation;
void generateOrientation();
void updateFollowMode( float deltaTime );
};

View file

@ -41,69 +41,53 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
4,5,6, 4,6,7 }; // Z+ .
VoxelSystem::VoxelSystem() {
voxelsRendered = 0;
tree = new VoxelTree();
pthread_mutex_init(&bufferWriteLock, NULL);
_voxelsInArrays = _voxelsUpdated = 0;
_tree = new VoxelTree();
pthread_mutex_init(&_bufferWriteLock, NULL);
}
VoxelSystem::~VoxelSystem() {
delete[] readVerticesArray;
delete[] writeVerticesArray;
delete[] readColorsArray;
delete[] writeColorsArray;
delete tree;
pthread_mutex_destroy(&bufferWriteLock);
delete[] _readVerticesArray;
delete[] _writeVerticesArray;
delete[] _readColorsArray;
delete[] _writeColorsArray;
delete[] _voxelDirtyArray;
delete _tree;
pthread_mutex_destroy(&_bufferWriteLock);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Method: VoxelSystem::loadVoxelsFile()
// Description: Loads HiFidelity encoded Voxels from a binary file. The current file
// format is a stream of single voxels with NO color data. Currently
// colors are set randomly
// Complaints: Brad :)
// To Do: Need to add color data to the file.
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
tree->loadVoxelsFile(fileName,wantColorRandomizer);
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
copyWrittenDataToReadArrays();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Method: VoxelSystem::createSphere()
// Description: Creates a sphere of voxels in the local system at a given location/radius
// To Do: Move this function someplace better? I put it here because we need a
// mechanism to tell the system to redraw it's arrays after voxels are done
// being added. This is a concept mostly only understood by VoxelSystem.
// Complaints: Brad :)
void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
_tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer);
setupNewVoxelsForDrawing();
}
long int VoxelSystem::getVoxelsCreated() {
return tree->voxelsCreated;
return _tree->voxelsCreated;
}
float VoxelSystem::getVoxelsCreatedPerSecondAverage() {
return (1 / tree->voxelsCreatedStats.getEventDeltaAverage());
return (1 / _tree->voxelsCreatedStats.getEventDeltaAverage());
}
long int VoxelSystem::getVoxelsColored() {
return tree->voxelsColored;
return _tree->voxelsColored;
}
float VoxelSystem::getVoxelsColoredPerSecondAverage() {
return (1 / tree->voxelsColoredStats.getEventDeltaAverage());
return (1 / _tree->voxelsColoredStats.getEventDeltaAverage());
}
long int VoxelSystem::getVoxelsBytesRead() {
return tree->voxelsBytesRead;
return _tree->voxelsBytesRead;
}
float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
return _tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
}
int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
@ -114,11 +98,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
switch(command) {
case PACKET_HEADER_VOXEL_DATA:
// ask the VoxelTree to read the bitstream into the tree
tree->readBitstreamToTree(voxelData, numBytes - 1);
_tree->readBitstreamToTree(voxelData, numBytes - 1);
break;
case PACKET_HEADER_ERASE_VOXEL:
// ask the tree to read the "remove" bitstream
tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
_tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
break;
case PACKET_HEADER_Z_COMMAND:
@ -135,7 +119,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
while (totalLength <= numBytes) {
if (0==strcmp(command,(char*)"erase all")) {
printLog("got Z message == erase all\n");
tree->eraseAllVoxels();
_tree->eraseAllVoxels();
_voxelsInArrays = 0; // better way to do this??
}
if (0==strcmp(command,(char*)"add scene")) {
printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
@ -150,78 +135,87 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
}
void VoxelSystem::setupNewVoxelsForDrawing() {
// reset the verticesEndPointer so we're writing to the beginning of the array
writeVerticesEndPointer = writeVerticesArray;
// call recursive function to populate in memory arrays
// it will return the number of voxels added
glm::vec3 treeRoot = glm::vec3(0,0,0);
voxelsRendered = treeToArrays(tree->rootNode, treeRoot);
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
if (_voxelsUpdated) {
_voxelsDirty=true;
}
// copy the newly written data to the arrays designated for reading
copyWrittenDataToReadArrays();
}
void VoxelSystem::copyWrittenDataToReadArrays() {
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&bufferWriteLock);
// store a pointer to the current end so it doesn't change during copy
GLfloat *endOfCurrentVerticesData = writeVerticesEndPointer;
// copy the vertices and colors
memcpy(readVerticesArray, writeVerticesArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLfloat));
memcpy(readColorsArray, writeColorsArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLubyte));
// set the read vertices end pointer to the correct spot so the GPU knows how much to pull
readVerticesEndPointer = readVerticesArray + (endOfCurrentVerticesData - writeVerticesArray);
pthread_mutex_unlock(&bufferWriteLock);
if (_voxelsDirty) {
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&_bufferWriteLock);
int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
pthread_mutex_unlock(&_bufferWriteLock);
}
}
int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) {
int voxelsAdded = 0;
float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE);
glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition();
int VoxelSystem::newTreeToArrays(VoxelNode* node) {
assert(_viewFrustum); // you must set up _viewFrustum before calling this
int voxelsUpdated = 0;
float distanceToNode = node->distanceToCamera(*_viewFrustum);
float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1);
float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2);
bool inBoundary = (distanceToNode <= boundary);
bool inChildBoundary = (distanceToNode <= childBoundary);
bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
// debug LOD code
glm::vec3 debugNodePosition;
copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition);
float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) +
powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) +
powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2));
int renderLevel = *currentNode->octalCode + 1;
int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel);
bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring
if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) {
for (int i = 0; i < 8; i++) {
// check if there is a child here
if (currentNode->children[i] != NULL) {
glm::vec3 childNodePosition;
copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition);
childNodePosition *= (float)TREE_SCALE; // scale it up
voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition);
}
node->setShouldRender(shouldRender);
// let children figure out their renderness
for (int i = 0; i < 8; i++) {
if (node->children[i]) {
voxelsUpdated += newTreeToArrays(node->children[i]);
}
}
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us
if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) {
glm::vec3 startVertex;
float voxelScale = 0;
// If we're should render, use our legit location and scale,
if (node->getShouldRender()) {
copyFirstVertexForCode(node->octalCode, (float*)&startVertex);
voxelScale = (1 / powf(2, *node->octalCode));
} else {
// if we shouldn't render then set out location to some infinitely distant location,
// and our scale as infinitely small
startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX;
voxelScale = 0;
}
// if we didn't get any voxels added then we're a leaf
// add our vertex and color information to the interleaved array
if (voxelsAdded == 0 && currentNode->isColored()) {
float startVertex[3];
copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex);
float voxelScale = 1 / powf(2, *currentNode->octalCode);
// If this node has not yet been written to the array, then add it to the end of the array.
glBufferIndex nodeIndex;
if (node->isKnownBufferIndex()) {
nodeIndex = node->getBufferIndex();
} else {
nodeIndex = _voxelsInArrays;
}
_voxelDirtyArray[nodeIndex] = true;
// populate the array with points for the 8 vertices
// and RGB color for each added vertex
for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) {
*writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale);
*(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3];
writeVerticesEndPointer++;
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
*(writeColorsAt +j) = node->getColor()[j % 3];
}
voxelsAdded++;
if (!node->isKnownBufferIndex()) {
node->setBufferIndex(nodeIndex);
_voxelsInArrays++; // our know vertices in the arrays
}
voxelsUpdated++;
node->clearDirtyBit();
}
return voxelsAdded;
return voxelsUpdated;
}
VoxelSystem* VoxelSystem::clone() const {
@ -230,20 +224,30 @@ VoxelSystem* VoxelSystem::clone() const {
}
void VoxelSystem::init() {
// prep the data structures for incoming voxel data
writeVerticesEndPointer = writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
readVerticesEndPointer = readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
GLuint *indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
// When we change voxels representations in the arrays, we'll update this
_voxelsDirty = false;
_voxelsInArrays = 0;
// we will track individual dirty sections with this array of bools
_voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM];
memset(_voxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool));
// prep the data structures for incoming voxel data
_writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
_readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
_writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
_readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
// populate the indicesArray
// this will not change given new voxels, so we can set it all up now
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
// fill the indices array
int voxelIndexOffset = n * INDICES_PER_VOXEL;
GLuint *currentIndicesPos = indicesArray + voxelIndexOffset;
GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
int startIndex = (n * VERTICES_PER_VOXEL);
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
@ -252,8 +256,8 @@ void VoxelSystem::init() {
}
}
GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
GLfloat *normalsArrayEndPointer = normalsArray;
GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
GLfloat* normalsArrayEndPointer = normalsArray;
// populate the normalsArray
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
@ -263,25 +267,25 @@ void VoxelSystem::init() {
}
// VBO for the verticesArray
glGenBuffers(1, &vboVerticesID);
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
glGenBuffers(1, &_vboVerticesID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
// VBO for the normalsArray
glGenBuffers(1, &vboNormalsID);
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
glGenBuffers(1, &_vboNormalsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
glBufferData(GL_ARRAY_BUFFER,
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM,
normalsArray, GL_STATIC_DRAW);
// VBO for colorsArray
glGenBuffers(1, &vboColorsID);
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
glGenBuffers(1, &_vboColorsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
// VBO for the indicesArray
glGenBuffers(1, &vboIndicesID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
glGenBuffers(1, &_vboIndicesID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM,
indicesArray, GL_STATIC_DRAW);
@ -291,45 +295,61 @@ void VoxelSystem::init() {
delete[] normalsArray;
}
void VoxelSystem::render() {
glPushMatrix();
if (readVerticesEndPointer != readVerticesArray) {
// try to lock on the buffer write
// just avoid pulling new data if it is currently being written
if (pthread_mutex_trylock(&bufferWriteLock) == 0) {
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray);
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray);
readVerticesEndPointer = readVerticesArray;
pthread_mutex_unlock(&bufferWriteLock);
void VoxelSystem::updateVBOs() {
if (_voxelsDirty) {
glBufferIndex segmentStart = 0;
glBufferIndex segmentEnd = 0;
bool inSegment = false;
for (glBufferIndex i = 0; i < _voxelsInArrays; i++) {
if (!inSegment) {
if (_voxelDirtyArray[i]) {
segmentStart = i;
inSegment = true;
_voxelDirtyArray[i] = false; // consider us clean!
}
} else {
if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) {
segmentEnd = i;
inSegment = false;
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
}
}
}
_voxelsDirty = false;
}
}
void VoxelSystem::render() {
glPushMatrix();
updateVBOs();
// tell OpenGL where to find vertex and color information
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
glNormalPointer(GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
// draw the number of voxels we have
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
glScalef(10, 10, 10);
glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0);
// deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
@ -344,25 +364,12 @@ void VoxelSystem::render() {
glPopMatrix();
}
void VoxelSystem::simulate(float deltaTime) {
}
int VoxelSystem::_nodeCount = 0;
bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) {
// we do our operations on the way up!
if (down) {
return true;
}
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
if (node->isColored()) {
nodeColor newColor = { 0,0,0,1 };
newColor[0] = randomColorValue(150);
newColor[1] = randomColorValue(150);
newColor[1] = randomColorValue(150);
nodeColor newColor = { randomColorValue(150), randomColorValue(150), randomColorValue(150), 1 };
node->setColor(newColor);
}
return true;
@ -370,43 +377,26 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa
void VoxelSystem::randomizeVoxelColors() {
_nodeCount = 0;
tree->recurseTreeWithOperation(randomColorOperation);
printLog("setting randomized true color for %d nodes\n",_nodeCount);
_tree->recurseTreeWithOperation(randomColorOperation);
printLog("setting randomized true color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) {
// we do our operations on the way up!
if (down) {
return true;
}
bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
// always false colorize
unsigned char newR = randomColorValue(150);
unsigned char newG = randomColorValue(150);
unsigned char newB = randomColorValue(150);
node->setFalseColor(newR,newG,newB);
node->setFalseColor(randomColorValue(150), randomColorValue(150), randomColorValue(150));
return true; // keep going!
}
void VoxelSystem::falseColorizeRandom() {
_nodeCount = 0;
tree->recurseTreeWithOperation(falseColorizeRandomOperation);
printLog("setting randomized false color for %d nodes\n",_nodeCount);
_tree->recurseTreeWithOperation(falseColorizeRandomOperation);
printLog("setting randomized false color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) {
// we do our operations on the way up!
if (down) {
return true;
}
bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
node->setFalseColored(false);
return true;
@ -414,90 +404,45 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD
void VoxelSystem::trueColorize() {
_nodeCount = 0;
tree->recurseTreeWithOperation(trueColorizeOperation);
printLog("setting true color for %d nodes\n",_nodeCount);
_tree->recurseTreeWithOperation(trueColorizeOperation);
printLog("setting true color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
// Will false colorize voxels that are not in view
bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) {
// we do our operations on the way up!
if (down) {
return true;
}
bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) {
const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData;
_nodeCount++;
// only do this for truely colored voxels...
if (node->isColored()) {
// If the voxel is outside of the view frustum, then false color it red
if (!node->isInView(*viewFrustum)) {
// Out of view voxels are colored RED
unsigned char newR = 255;
unsigned char newG = 0;
unsigned char newB = 0;
node->setFalseColor(newR,newG,newB);
node->setFalseColor(255, 0, 0);
}
}
return true; // keep going!
}
void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {
_nodeCount = 0;
tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
printLog("setting in view false color for %d nodes\n",_nodeCount);
_tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
printLog("setting in view false color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}
// Will false colorize voxels based on distance from view
bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) {
// we do our operations on the way up!
if (down) {
return true;
}
bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) {
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
// only do this for truly colored voxels...
if (node->isColored()) {
// We need our distance for both up and down
glm::vec3 nodePosition;
float* startVertex = firstVertexForCode(node->octalCode);
nodePosition.x = startVertex[0];
nodePosition.y = startVertex[1];
nodePosition.z = startVertex[2];
delete startVertex;
// scale up the node position
nodePosition = nodePosition*(float)TREE_SCALE;
float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE);
glm::vec3 viewerPosition = viewFrustum->getPosition();
float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) +
powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) +
powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2));
// actually colorize
float distance = node->distanceToCamera(*viewFrustum);
_nodeCount++;
float distanceRatio = (_minDistance==_maxDistance) ? 1 : (distance - _minDistance)/(_maxDistance - _minDistance);
float distanceRatio = (_minDistance == _maxDistance) ? 1 : (distance - _minDistance) / (_maxDistance - _minDistance);
// We want to colorize this in 16 bug chunks of color
const unsigned char maxColor = 255;
const unsigned char colorBands = 16;
const unsigned char gradientOver = 128;
unsigned char colorBand = (colorBands*distanceRatio);
unsigned char newR = (colorBand*(gradientOver/colorBands))+(maxColor-gradientOver);
unsigned char newG = 0;
unsigned char newB = 0;
node->setFalseColor(newR,newG,newB);
unsigned char colorBand = (colorBands * distanceRatio);
node->setFalseColor((colorBand * (gradientOver / colorBands)) + (maxColor - gradientOver), 0, 0);
}
return true; // keep going!
}
@ -508,44 +453,18 @@ float VoxelSystem::_minDistance = FLT_MAX;
// Helper function will get the distance from view range, would be nice if you could just keep track
// of this as voxels are created and/or colored... seems like some transform math could do that so
// we wouldn't need to do two passes of the tree
bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) {
// we do our operations on the way up!
if (down) {
return true;
}
bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) {
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
// only do this for truly colored voxels...
if (node->isColored()) {
// We need our distance for both up and down
glm::vec3 nodePosition;
float* startVertex = firstVertexForCode(node->octalCode);
nodePosition.x = startVertex[0];
nodePosition.y = startVertex[1];
nodePosition.z = startVertex[2];
delete startVertex;
// scale up the node position
nodePosition = nodePosition*(float)TREE_SCALE;
float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE);
glm::vec3 viewerPosition = viewFrustum->getPosition();
float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) +
powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) +
powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2));
// on way down, calculate the range of distances
float distance = node->distanceToCamera(*viewFrustum);
// calculate the range of distances
if (distance > _maxDistance) {
_maxDistance = distance;
}
if (distance < _minDistance) {
_minDistance = distance;
}
_nodeCount++;
}
return true; // keep going!
@ -553,15 +472,14 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down,
void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
_nodeCount = 0;
_maxDistance = 0.0;
_minDistance = FLT_MAX;
tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
printLog("determining distance range for %d nodes\n",_nodeCount);
_tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
printLog("determining distance range for %d nodes\n", _nodeCount);
_nodeCount = 0;
tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
printLog("setting in distance false color for %d nodes\n",_nodeCount);
_tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
printLog("setting in distance false color for %d nodes\n", _nodeCount);
setupNewVoxelsForDrawing();
}

View file

@ -29,12 +29,16 @@ public:
int parseData(unsigned char* sourceBuffer, int numBytes);
VoxelSystem* clone() const;
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; };
void init();
void simulate(float deltaTime);
void simulate(float deltaTime) { };
void render();
void setVoxelsRendered(int v) {voxelsRendered = v;};
int getVoxelsRendered() {return voxelsRendered;};
unsigned long getVoxelsUpdated() const {return _voxelsUpdated;};
unsigned long getVoxelsRendered() const {return _voxelsInArrays;};
void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; };
void setCamera(Camera* newCamera) { _camera = newCamera; };
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
@ -57,36 +61,42 @@ public:
private:
// Operation functions for tree recursion methods
static int _nodeCount;
static bool randomColorOperation(VoxelNode* node, bool down, void* extraData);
static bool falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData);
static bool trueColorizeOperation(VoxelNode* node, bool down, void* extraData);
static bool falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData);
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData);
static bool getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData);
static bool randomColorOperation(VoxelNode* node, void* extraData);
static bool falseColorizeRandomOperation(VoxelNode* node, void* extraData);
static bool trueColorizeOperation(VoxelNode* node, void* extraData);
static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData);
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData);
static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData);
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
static float _maxDistance;
static float _minDistance;
int voxelsRendered;
Avatar* _viewerAvatar;
Camera* _camera;
VoxelTree *tree;
GLfloat *readVerticesArray;
GLubyte *readColorsArray;
GLfloat *readVerticesEndPointer;
GLfloat *writeVerticesArray;
GLubyte *writeColorsArray;
GLfloat *writeVerticesEndPointer;
GLuint vboVerticesID;
GLuint vboNormalsID;
GLuint vboColorsID;
GLuint vboIndicesID;
pthread_mutex_t bufferWriteLock;
VoxelTree* _tree;
GLfloat* _readVerticesArray;
GLubyte* _readColorsArray;
GLfloat* _writeVerticesArray;
GLubyte* _writeColorsArray;
bool* _voxelDirtyArray;
unsigned long _voxelsUpdated;
unsigned long _voxelsInArrays;
GLuint _vboVerticesID;
GLuint _vboNormalsID;
GLuint _vboColorsID;
GLuint _vboIndicesID;
pthread_mutex_t _bufferWriteLock;
int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition);
ViewFrustum* _viewFrustum;
int newTreeToArrays(VoxelNode *currentNode);
void setupNewVoxelsForDrawing();
void copyWrittenDataToReadArrays();
void updateVBOs();
bool _voxelsDirty;
};
#endif

View file

@ -113,11 +113,11 @@ bool wantColorRandomizer = true; // for addSphere and load file
Oscilloscope audioScope(256,200,true);
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
Avatar myAvatar(true); // The rendered avatar of oneself
Camera myCamera; // My view onto the world (sometimes on myself :)
Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
Avatar myAvatar(true); // The rendered avatar of oneself
Camera myCamera; // My view onto the world (sometimes on myself :)
Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
// Starfield information
char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
@ -236,7 +236,7 @@ void displayStats(void)
drawtext(10, statsVerticalOffset + 49, 0.10f, 0, 1.0, 0, stats);
std::stringstream voxelStats;
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() << " Updated: " << voxels.getVoxelsUpdated();
drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
@ -502,31 +502,19 @@ void loadViewFrustum(ViewFrustum& viewFrustum) {
glm::vec3 up;
glm::vec3 right;
float fov, nearClip, farClip;
float yaw, pitch, roll;
// Camera or Head?
if (::cameraFrustum) {
position = ::myCamera.getPosition();
position = ::myCamera.getPosition();
} else {
position = ::myAvatar.getHeadPosition();
position = ::myAvatar.getHeadPosition();
}
// This bit of hackery is all because our Cameras report the incorrect yaw.
// For whatever reason, the camera has a yaw set to 180.0-trueYaw, so we basically
// need to get the "yaw" from the camera and adjust it to be the trueYaw
yaw = -(::myCamera.getOrientation().getYaw()-180);
pitch = ::myCamera.getOrientation().getPitch();
roll = ::myCamera.getOrientation().getRoll();
fov = ::myCamera.getFieldOfView();
nearClip = ::myCamera.getNearClip();
farClip = ::myCamera.getFarClip();
// We can't use the camera's Orientation because of it's broken yaw. so we make a new
// correct orientation to get our vectors
Orientation o;
o.yaw(yaw);
o.pitch(pitch);
o.roll(roll);
Orientation o = ::myCamera.getOrientation();
direction = o.getFront();
up = o.getUp();
@ -716,16 +704,16 @@ void display(void)
glMaterialfv(GL_FRONT, GL_SPECULAR, specular_color);
glMateriali(GL_FRONT, GL_SHININESS, 96);
// camera settings
if ( ::lookingInMirror ) {
// set the camera to looking at my own face
myCamera.setTargetPosition ( myAvatar.getHeadPosition() );
myCamera.setTargetYaw ( - myAvatar.getBodyYaw() );
myCamera.setPitch ( 0.0 );
myCamera.setRoll ( 0.0 );
myCamera.setUpShift ( 0.0 );
myCamera.setDistance ( 0.2 );
myCamera.setTightness ( 100.0f );
// camera settings
if ( ::lookingInMirror ) {
// set the camera to looking at my own face
myCamera.setTargetPosition ( myAvatar.getHeadPosition() );
myCamera.setTargetYaw ( myAvatar.getBodyYaw() - 180.0f ); // 180 degrees from body yaw
myCamera.setPitch ( 0.0 );
myCamera.setRoll ( 0.0 );
myCamera.setUpShift ( 0.0 );
myCamera.setDistance ( 0.2 );
myCamera.setTightness ( 100.0f );
} else {
//float firstPersonPitch = 20.0f;
@ -800,17 +788,17 @@ void display(void)
*/
} else {
myCamera.setPitch (thirdPersonPitch );
myCamera.setPitch (thirdPersonPitch );
myCamera.setUpShift (thirdPersonUpShift );
myCamera.setDistance (thirdPersonDistance );
myCamera.setTightness(thirdPersonTightness);
}
myCamera.setTargetPosition( myAvatar.getHeadPosition() );
myCamera.setTargetYaw ( 180.0 - myAvatar.getBodyYaw() );
myCamera.setRoll ( 0.0 );
myCamera.setTargetPosition( myAvatar.getHeadPosition() );
myCamera.setTargetYaw ( myAvatar.getBodyYaw() );
myCamera.setRoll ( 0.0 );
}
// important...
myCamera.update( 1.f/FPS );
@ -827,23 +815,25 @@ void display(void)
if (::viewFrustumFromOffset && ::frustumOn) {
// set the camera to third-person view but offset so we can see the frustum
viewFrustumOffsetCamera.setTargetYaw( 180.0 - myAvatar.getBodyYaw() + ::viewFrustumOffsetYaw );
viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch );
viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll );
viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp );
viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance );
viewFrustumOffsetCamera.update(1.f/FPS);
whichCamera = viewFrustumOffsetCamera;
}
// set the camera to third-person view but offset so we can see the frustum
viewFrustumOffsetCamera.setTargetYaw( ::viewFrustumOffsetYaw + myAvatar.getBodyYaw() );
viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch );
viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll );
viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp );
viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance );
viewFrustumOffsetCamera.update(1.f/FPS);
whichCamera = viewFrustumOffsetCamera;
}
// transform view according to whichCamera
// could be myCamera (if in normal mode)
// or could be viewFrustumOffsetCamera if in offset mode
// I changed the ordering here - roll is FIRST (JJV)
glRotatef ( whichCamera.getRoll(), 0, 0, 1 );
glRotatef ( whichCamera.getPitch(), 1, 0, 0 );
glRotatef ( whichCamera.getYaw(), 0, 1, 0 );
glRotatef ( whichCamera.getRoll(), IDENTITY_FRONT.x, IDENTITY_FRONT.y, IDENTITY_FRONT.z );
glRotatef ( whichCamera.getPitch(), IDENTITY_RIGHT.x, IDENTITY_RIGHT.y, IDENTITY_RIGHT.z );
glRotatef ( 180.0 - whichCamera.getYaw(), IDENTITY_UP.x, IDENTITY_UP.y, IDENTITY_UP.z );
glTranslatef( -whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z );
if (::starsOn) {
@ -859,18 +849,18 @@ void display(void)
// draw a red sphere
float sphereRadius = 0.25f;
glColor3f(1,0,0);
glPushMatrix();
glutSolidSphere( sphereRadius, 15, 15 );
glPopMatrix();
glPushMatrix();
glutSolidSphere( sphereRadius, 15, 15 );
glPopMatrix();
//draw a grid ground plane....
drawGroundPlaneGrid( 5.0f, 9 );
//draw a grid ground plane....
drawGroundPlaneGrid( 5.0f, 9 );
// Draw voxels
if ( showingVoxels )
{
voxels.render();
}
if ( showingVoxels )
{
voxels.render();
}
// Render avatars of other agents
AgentList* agentList = AgentList::getInstance();
@ -1619,6 +1609,8 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
int main(int argc, const char * argv[])
{
voxels.setViewFrustum(&::viewFrustum);
shared_lib::printLog = & ::printLog;
voxels_lib::printLog = & ::printLog;
avatars_lib::printLog = & ::printLog;

View file

@ -9,165 +9,116 @@
#include <SharedUtil.h>
#include "avatars_Log.h"
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
//#include "Util.h"
using avatars_lib::printLog;
// XXXBHG - this test has not yet been reworked to match the correct vector orientation
// of the coordinate system, so don't use it for now.
//
// tosh - yep, I noticed... :-)
//
static bool testingForNormalizationAndOrthogonality = false;
static const bool USING_QUATERNIONS = true;
Orientation::Orientation() {
setToIdentity();
}
void Orientation::setToIdentity() {
_yaw = 0.0;
_pitch = 0.0;
_roll = 0.0;
right = glm::vec3( -1.0f, 0.0f, 0.0f );
up = glm::vec3( 0.0f, 1.0f, 0.0f );
front = glm::vec3( 0.0f, 0.0f, 1.0f );
quat = glm::quat();
right = glm::vec3( IDENTITY_RIGHT );
up = glm::vec3( IDENTITY_UP );
front = glm::vec3( IDENTITY_FRONT );
}
void Orientation::set( Orientation o ) {
quat = o.quat;
right = o.right;
up = o.up;
front = o.front;
}
void Orientation::update() {
void Orientation::yaw( float angle ) {
float pitchRads = _pitch * PI_OVER_180;
float yawRads = _yaw * PI_OVER_180;
float rollRads = _roll * PI_OVER_180;
float radian = angle * PI_OVER_180;
glm::quat q(glm::vec3(pitchRads, -(yawRads), rollRads));
// Next, create a rotation matrix from that quaternion
glm::mat4 rotation;
rotation = glm::mat4_cast(q);
// Transform the original vectors by the rotation matrix to get the new vectors
glm::vec4 qup(0,1,0,0);
glm::vec4 qright(-1,0,0,0);
glm::vec4 qfront(0,0,1,0);
glm::vec4 upNew = qup*rotation;
glm::vec4 rightNew = qright*rotation;
glm::vec4 frontNew = qfront*rotation;
// Copy the answers to output vectors
up.x = upNew.x;
up.y = upNew.y;
up.z = upNew.z;
right.x = rightNew.x;
right.y = rightNew.y;
right.z = rightNew.z;
front.x = frontNew.x;
front.y = frontNew.y;
front.z = frontNew.z;
if ( testingForNormalizationAndOrthogonality ) { testForOrthogonalAndNormalizedVectors( EPSILON ); }
}
void Orientation::yaw(float angle) {
// remember the value for any future changes to other angles
_yaw = angle;
update();
if ( USING_QUATERNIONS ) {
rotateAndGenerateDirections( glm::quat( glm::vec3( 0.0f, -radian, 0.0f )) );
} else {
float s = sin(radian);
float c = cos(radian);
glm::vec3 cosineFront = front * c;
glm::vec3 cosineRight = right * c;
glm::vec3 sineFront = front * s;
glm::vec3 sineRight = right * s;
front = cosineFront - sineRight;
right = cosineRight + sineFront;
}
}
void Orientation::pitch( float angle ) {
// remember the value for any future changes to other angles
_pitch = angle;
update();
}
float radian = angle * PI_OVER_180;
if ( USING_QUATERNIONS ) {
rotateAndGenerateDirections( glm::quat( glm::vec3( radian, 0.0f, 0.0f ) ) );
} else {
float s = sin(radian);
float c = cos(radian);
glm::vec3 cosineUp = up * c;
glm::vec3 cosineFront = front * c;
glm::vec3 sineUp = up * s;
glm::vec3 sineFront = front * s;
up = cosineUp - sineFront;
front = cosineFront + sineUp;
}
}
void Orientation::roll( float angle ) {
_roll = angle;
update();
float radian = angle * PI_OVER_180;
if ( USING_QUATERNIONS ) {
rotateAndGenerateDirections( glm::quat( glm::vec3( 0.0f, 0.0f, radian )) );
} else {
float s = sin(radian);
float c = cos(radian);
glm::vec3 cosineUp = up * c;
glm::vec3 cosineRight = right * c;
glm::vec3 sineUp = up * s;
glm::vec3 sineRight = right * s;
up = cosineUp - sineRight;
right = cosineRight + sineUp;
}
}
void Orientation::rotate( float p, float y, float r ) {
pitch(p);
yaw (y);
roll (r);
}
void Orientation::rotate( glm::vec3 eulerAngles ) {
//this needs to be optimized!
pitch(eulerAngles.x);
yaw (eulerAngles.y);
roll (eulerAngles.z);
}
void Orientation::rotate( glm::quat rotation ) {
rotateAndGenerateDirections(rotation);
}
void Orientation::setRightUpFront( const glm::vec3 &r, const glm::vec3 &u, const glm::vec3 &f ) {
right = r;
up = u;
front = f;
void Orientation::rotateAndGenerateDirections( glm::quat rotation ) {
quat = quat * rotation;
glm::mat4 rotationMatrix = glm::mat4_cast(quat);
right = glm::vec3( glm::vec4( IDENTITY_RIGHT, 0.0f ) * rotationMatrix );
up = glm::vec3( glm::vec4( IDENTITY_UP, 0.0f ) * rotationMatrix );
front = glm::vec3( glm::vec4( IDENTITY_FRONT, 0.0f ) * rotationMatrix );
}
void Orientation::testForOrthogonalAndNormalizedVectors( float epsilon ) {
// XXXBHG - this test has not yet been reworked to match the correct vector orientation
// of the coordinate system
// bail for now, assume all is good
return;
// make sure vectors are normalized (or close enough to length 1.0)
float rightLength = glm::length( right );
float upLength = glm::length( up );
float frontLength = glm::length( front );
if (( rightLength > 1.0f + epsilon )
|| ( rightLength < 1.0f - epsilon )) {
printLog( "Error in Orientation class: right direction length is %f \n", rightLength );
}
assert ( rightLength > 1.0f - epsilon );
assert ( rightLength < 1.0f + epsilon );
if (( upLength > 1.0f + epsilon )
|| ( upLength < 1.0f - epsilon )) {
printLog( "Error in Orientation class: up direction length is %f \n", upLength );
}
assert ( upLength > 1.0f - epsilon );
assert ( upLength < 1.0f + epsilon );
if (( frontLength > 1.0f + epsilon )
|| ( frontLength < 1.0f - epsilon )) {
printLog( "Error in Orientation class: front direction length is %f \n", frontLength );
}
assert ( frontLength > 1.0f - epsilon );
assert ( frontLength < 1.0f + epsilon );
// make sure vectors are orthogonal (or close enough)
glm::vec3 rightCross = glm::cross( up, front );
glm::vec3 upCross = glm::cross( front, right );
glm::vec3 frontCross = glm::cross( right, up );
float rightDiff = glm::length( rightCross - right );
float upDiff = glm::length( upCross - up );
float frontDiff = glm::length( frontCross - front );
if ( rightDiff > epsilon ) {
printLog( "Error in Orientation class: right direction not orthogonal to up and/or front. " );
printLog( "The tested cross of up and front is off by %f \n", rightDiff );
}
assert ( rightDiff < epsilon );
if ( upDiff > epsilon ) {
printLog( "Error in Orientation class: up direction not orthogonal to front and/or right. " );
printLog( "The tested cross of front and right is off by %f \n", upDiff );
}
assert ( upDiff < epsilon );
if ( frontDiff > epsilon ) {
printLog( "Error in Orientation class: front direction not orthogonal to right and/or up. " );
printLog( "The tested cross of right and up is off by %f \n", frontDiff );
}
assert ( frontDiff < epsilon );
}

View file

@ -1,6 +1,5 @@
//-----------------------------------------------------------
//
// Created by Jeffrey Ventrella
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//-----------------------------------------------------------
@ -8,52 +7,47 @@
#ifndef __interface__orientation__
#define __interface__orientation__
#include <cmath> // with this work? "Math.h"
#include <cmath>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
enum Axis
{
ORIENTATION_RIGHT_AXIS,
ORIENTATION_UP_AXIS,
ORIENTATION_FRONT_AXIS
};
// 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 );
class Orientation
{
private:
float _yaw;
float _pitch;
float _roll;
public:
Orientation();
void set( Orientation );
void setToIdentity();
void pitch( float p );
void yaw ( float y );
void roll ( float r );
void rotate( float pitch, float yaw, float roll );
void rotate( glm::vec3 EulerAngles );
void rotate( glm::quat quaternion );
const glm::vec3 & getRight() const { return right; }
const glm::vec3 & getUp () const { return up; }
const glm::vec3 & getFront() const { return front; }
const glm::vec3 & getIdentityRight() const { return IDENTITY_RIGHT; }
const glm::vec3 & getIdentityUp () const { return IDENTITY_UP; }
const glm::vec3 & getIdentityFront() const { return IDENTITY_FRONT; }
private:
glm::quat quat;
glm::vec3 right;
glm::vec3 up;
glm::vec3 front;
void update(); // actually updates the vectors from yaw, pitch, roll
public:
Orientation();
void yaw ( float );
void pitch ( float );
void roll ( float );
float getYaw() { return _yaw; };
float getPitch(){ return _pitch; };
float getRoll(){ return _roll; };
void set( Orientation );
void setToIdentity();
const glm::vec3& getRight() const { return right; }
const glm::vec3& getUp() const { return up; }
const glm::vec3& getFront() const { return front; }
void setRightUpFront( const glm::vec3 &, const glm::vec3 &, const glm::vec3 & );
private:
void testForOrthogonalAndNormalizedVectors( float epsilon );
void rotateAndGenerateDirections( glm::quat rotation );
};
#endif

View file

@ -21,4 +21,7 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
const int INDICES_PER_VOXEL = 3 * 12;
const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
typedef unsigned long int glBufferIndex;
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
#endif

View file

@ -30,6 +30,10 @@ VoxelNode::VoxelNode() {
for (int i = 0; i < 8; i++) {
children[i] = NULL;
}
_glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
_isDirty = true;
_shouldRender = false;
}
VoxelNode::~VoxelNode() {
@ -43,6 +47,14 @@ VoxelNode::~VoxelNode() {
}
}
void VoxelNode::setShouldRender(bool shouldRender) {
// if shouldRender is changing, then consider ourselves dirty
if (shouldRender != _shouldRender) {
_shouldRender = shouldRender;
_isDirty = true;
}
}
void VoxelNode::getAABox(AABox& box) const {
glm::vec3 corner;
@ -59,16 +71,19 @@ void VoxelNode::getAABox(AABox& box) const {
}
void VoxelNode::addChildAtIndex(int childIndex) {
children[childIndex] = new VoxelNode();
if (!children[childIndex]) {
children[childIndex] = new VoxelNode();
// XXXBHG - When the node is constructed, it should be cleanly set up as
// true colored, but for some reason, not so much. I've added a a basecamp
// to-do to research this. But for now we'll use belt and suspenders and set
// it to not-false-colored here!
children[childIndex]->setFalseColored(false);
// XXXBHG - When the node is constructed, it should be cleanly set up as
// true colored, but for some reason, not so much. I've added a a basecamp
// to-do to research this. But for now we'll use belt and suspenders and set
// it to not-false-colored here!
children[childIndex]->setFalseColored(false);
// give this child its octal code
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
// give this child its octal code
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
_isDirty = true;
}
}
// will average the child colors...
@ -104,26 +119,35 @@ void VoxelNode::setColorFromAverageOfChildren() {
// the actual NO_FALSE_COLOR version are inline in the VoxelNode.h
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) {
_falseColored=true;
_currentColor[0] = red;
_currentColor[1] = green;
_currentColor[2] = blue;
_currentColor[3] = 1; // XXXBHG - False colors are always considered set
if (_falseColored != true || _currentColor[0] != red || _currentColor[1] != green || _currentColor[2] != blue) {
_falseColored=true;
_currentColor[0] = red;
_currentColor[1] = green;
_currentColor[2] = blue;
_currentColor[3] = 1; // XXXBHG - False colors are always considered set
_isDirty = true;
}
}
void VoxelNode::setFalseColored(bool isFalseColored) {
// if we were false colored, and are no longer false colored, then swap back
if (_falseColored && !isFalseColored) {
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
if (_falseColored != isFalseColored) {
// if we were false colored, and are no longer false colored, then swap back
if (_falseColored && !isFalseColored) {
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
}
_falseColored = isFalseColored;
_isDirty = true;
}
_falseColored = isFalseColored;
};
void VoxelNode::setColor(const nodeColor& color) {
memcpy(&_trueColor,&color,sizeof(nodeColor));
if (!_falseColored) {
memcpy(&_currentColor,&color,sizeof(nodeColor));
if (_trueColor[0] != color[0] || _trueColor[1] != color[1] || _trueColor[2] != color[2]) {
memcpy(&_trueColor,&color,sizeof(nodeColor));
if (!_falseColored) {
memcpy(&_currentColor,&color,sizeof(nodeColor));
}
_isDirty = true;
}
}
#endif
@ -199,7 +223,6 @@ void VoxelNode::printDebugDetails(const char* label) const {
printOctalCode(octalCode);
}
bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const {
AABox box;
getAABox(box);

View file

@ -11,6 +11,7 @@
#include "AABox.h"
#include "ViewFrustum.h"
#include "VoxelConstants.h"
typedef unsigned char colorPart;
typedef unsigned char nodeColor[4];
@ -22,6 +23,9 @@ private:
nodeColor _currentColor;
bool _falseColored;
#endif
glBufferIndex _glBufferIndex;
bool _isDirty;
bool _shouldRender;
public:
VoxelNode();
~VoxelNode();
@ -40,7 +44,14 @@ public:
bool isLeaf() const;
void getAABox(AABox& box) const;
void printDebugDetails(const char* label) const;
bool isDirty() const { return _isDirty; };
void clearDirtyBit() { _isDirty = false; };
glBufferIndex getBufferIndex() const { return _glBufferIndex; };
bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); };
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; };
void setShouldRender(bool shouldRender);
bool getShouldRender() const { return _shouldRender; }
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
void setFalseColor(colorPart red, colorPart green, colorPart blue);
void setFalseColored(bool isFalseColored);

View file

@ -58,16 +58,13 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo
// Recurses voxel node with an operation function
void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) {
// call the operation function going "down" first, stop deeper recursion if function returns false
if (operation(node,true,extraData)) {
for (int i = 0; i < sizeof(node->children)/sizeof(node->children[0]); i++) {
if (operation(node, extraData)) {
for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) {
VoxelNode* child = node->children[i];
if (child) {
recurseNodeWithOperation(child,operation,extraData);
recurseNodeWithOperation(child, operation, extraData);
}
}
// call operation on way back up
operation(node,false,extraData);
}
}

View file

@ -16,7 +16,7 @@
#include "VoxelNodeBag.h"
// Callback function, for recuseTreeWithOperation
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData);
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
class VoxelTree {
public:

View file

@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0;
const float MAX_CUBE = 0.05f;
const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000;
const int PACKETS_PER_CLIENT_PER_INTERVAL = 2;
const int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
@ -68,11 +68,9 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) {
}
int _nodeCount=0;
bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
if (down) {
if (node->isColored()){
_nodeCount++;
}
bool countVoxelsOperation(VoxelNode* node, void* extraData) {
if (node->isColored()){
_nodeCount++;
}
return true; // keep going
}
@ -80,7 +78,7 @@ bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
printf("adding scene of spheres...\n");
int sphereBaseSize = 256;
int sphereBaseSize = 512;
tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer);
printf("one sphere added...\n");