mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 16:13:28 +02:00
Merge remote-tracking branch 'upstream/master' into mouth-render
This commit is contained in:
commit
e040c927f5
12 changed files with 398 additions and 408 deletions
|
@ -918,31 +918,21 @@ void Application::idle() {
|
|||
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
if (_manualFirstPerson) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) {
|
||||
Camera::CameraFollowingAttributes a;
|
||||
a.upShift = 0.0f;
|
||||
a.distance = 0.0f;
|
||||
a.tightness = 100.0f;
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON, a);
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (_myAvatar.getIsNearInteractingOther()) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
|
||||
|
||||
Camera::CameraFollowingAttributes a;
|
||||
a.upShift = 0.0f;
|
||||
a.distance = 0.0f;
|
||||
a.tightness = 100.0f;
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON, a);
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
||||
Camera::CameraFollowingAttributes a;
|
||||
a.upShift = -0.2f;
|
||||
a.distance = 1.5f;
|
||||
a.tightness = 8.0f;
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON, a);
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -981,17 +971,11 @@ void Application::setHead(bool head) {
|
|||
#endif
|
||||
|
||||
if (head) {
|
||||
Camera::CameraFollowingAttributes a;
|
||||
a.upShift = 0.0f;
|
||||
a.distance = 0.2f;
|
||||
a.tightness = 100.0f;
|
||||
_myCamera.setMode(CAMERA_MODE_MIRROR, a);
|
||||
_myCamera.setMode(CAMERA_MODE_MIRROR);
|
||||
_myCamera.setModeShiftRate(100.0f);
|
||||
} else {
|
||||
Camera::CameraFollowingAttributes a;
|
||||
a.upShift = -0.2f;
|
||||
a.distance = 1.5f;
|
||||
a.tightness = 8.0f;
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON, a);
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1285,11 +1269,8 @@ void Application::init() {
|
|||
_stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0);
|
||||
|
||||
_myAvatar.setPosition(START_LOCATION);
|
||||
Camera::CameraFollowingAttributes a;
|
||||
a.upShift = -0.2f;
|
||||
a.distance = 1.5f;
|
||||
a.tightness = 8.0f;
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON, a);
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON );
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
_myAvatar.setDisplayingLookatVectors(false);
|
||||
|
||||
QCursor::setPos(_headMouseX, _headMouseY);
|
||||
|
|
|
@ -208,7 +208,7 @@ int audioCallback (const void* inputBuffer,
|
|||
// if we haven't fired off the flange effect, check if we should
|
||||
// TODO: lastMeasuredHeadYaw is now relative to body - check if this still works.
|
||||
|
||||
int lastYawMeasured = fabsf(interfaceAvatar->getLastMeasuredHeadYaw());
|
||||
int lastYawMeasured = fabsf(interfaceAvatar->getHeadYawRate());
|
||||
|
||||
if (!::samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) {
|
||||
// we should flange for one second
|
||||
|
|
|
@ -34,7 +34,7 @@ const float BODY_UPRIGHT_FORCE = 10.0;
|
|||
const float VELOCITY_DECAY = 5.0;
|
||||
const float MY_HAND_HOLDING_PULL = 0.2;
|
||||
const float YOUR_HAND_HOLDING_PULL = 1.0;
|
||||
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1500.0f;
|
||||
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f;
|
||||
const float BODY_SPRING_FORCE = 300.0f;
|
||||
const float BODY_SPRING_DECAY = 16.0f;
|
||||
const float COLLISION_RADIUS_SCALAR = 1.8;
|
||||
|
@ -54,15 +54,14 @@ const float JOINT_TOUCH_RANGE = 0.0005f;
|
|||
const float ANGULAR_RIGHTING_SPEED = 45.0f;
|
||||
const float FLOATING_HEIGHT = 0.13f;
|
||||
const bool USING_HEAD_LEAN = false;
|
||||
const float LEAN_SENSITIVITY = 0.15;
|
||||
const float LEAN_MAX = 0.45;
|
||||
const float LEAN_AVERAGING = 10.0;
|
||||
const float HEAD_RATE_MAX = 50.f;
|
||||
const float SKIN_COLOR[] = {1.0, 0.84, 0.66};
|
||||
const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63};
|
||||
const int NUM_BODY_CONE_SIDES = 9;
|
||||
|
||||
const float LEAN_SENSITIVITY = 0.15;
|
||||
const float LEAN_MAX = 0.45;
|
||||
const float LEAN_AVERAGING = 10.0;
|
||||
const float HEAD_RATE_MAX = 50.f;
|
||||
|
||||
float skinColor [] = {1.0, 0.84, 0.66};
|
||||
float darkSkinColor[] = {0.9, 0.78, 0.63};
|
||||
float lightBlue [] = {0.7, 0.8, 1.0 };
|
||||
|
||||
bool usingBigSphereCollisionTest = true;
|
||||
|
||||
|
@ -165,14 +164,6 @@ float Avatar::getAbsoluteHeadPitch() const {
|
|||
return _bodyPitch + _head.getPitch();
|
||||
}
|
||||
|
||||
void Avatar::setMousePressed(bool mousePressed) {
|
||||
_mousePressed = mousePressed;
|
||||
}
|
||||
|
||||
bool Avatar::getIsNearInteractingOther() {
|
||||
return _avatarTouch.getAbleToReachOtherAvatar();
|
||||
}
|
||||
|
||||
void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) {
|
||||
// Update yaw based on mouse behavior
|
||||
const float MOUSE_MOVE_RADIUS = 0.15f;
|
||||
|
@ -470,7 +461,8 @@ void Avatar::checkForMouseRayTouching() {
|
|||
}
|
||||
|
||||
void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction ) {
|
||||
_mouseRayOrigin = origin; _mouseRayDirection = direction;
|
||||
_mouseRayOrigin = origin;
|
||||
_mouseRayDirection = direction;
|
||||
}
|
||||
|
||||
void Avatar::updateHandMovementAndTouching(float deltaTime) {
|
||||
|
@ -485,6 +477,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
|
|||
|
||||
if (!_owningAgent) {
|
||||
_avatarTouch.setMyBodyPosition(_position);
|
||||
_avatarTouch.setMyOrientation(_orientation);
|
||||
|
||||
float closestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
|
@ -517,6 +510,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
|
|||
if (_interactingOther) {
|
||||
|
||||
_avatarTouch.setYourBodyPosition(_interactingOther->_position);
|
||||
_avatarTouch.setYourOrientation (_interactingOther->_orientation);
|
||||
_avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
|
||||
_avatarTouch.setYourHandState (_interactingOther->_handState);
|
||||
|
||||
|
@ -874,8 +868,8 @@ void Avatar::initializeSkeleton() {
|
|||
_joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.01 );
|
||||
_joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.01 );
|
||||
_joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.12, -0.01 );
|
||||
_joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.00 );
|
||||
_joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.14, -0.01 );
|
||||
_joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.04, 0.00 );
|
||||
|
||||
_joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, -0.01 );
|
||||
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.05, 0.0, -0.01 );
|
||||
|
@ -928,31 +922,6 @@ void Avatar::initializeSkeleton() {
|
|||
_joint[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025;
|
||||
_joint[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.025;
|
||||
|
||||
// specify the tightness of the springy positions as far as attraction to rigid body
|
||||
_joint[ AVATAR_JOINT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0;
|
||||
_joint[ AVATAR_JOINT_TORSO ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.8;
|
||||
_joint[ AVATAR_JOINT_CHEST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_NECK_BASE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.4;
|
||||
_joint[ AVATAR_JOINT_HEAD_BASE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_joint[ AVATAR_JOINT_LEFT_COLLAR ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_LEFT_ELBOW ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_LEFT_WRIST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.5;
|
||||
_joint[ AVATAR_JOINT_RIGHT_WRIST ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 0.3;
|
||||
_joint[ AVATAR_JOINT_LEFT_HIP ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_LEFT_KNEE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_LEFT_HEEL ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_LEFT_TOES ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_RIGHT_HIP ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_RIGHT_KNEE ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_RIGHT_HEEL ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
_joint[ AVATAR_JOINT_RIGHT_TOES ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
|
||||
|
||||
// to aid in hand-shaking and hand-holding, the right hand is not collidable
|
||||
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].isCollidable = false;
|
||||
_joint[ AVATAR_JOINT_RIGHT_WRIST ].isCollidable = false;
|
||||
|
@ -1102,15 +1071,6 @@ void Avatar::updateBodySprings(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
const glm::vec3& Avatar::getSpringyHeadPosition() const {
|
||||
return _joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition;
|
||||
}
|
||||
|
||||
const glm::vec3& Avatar::getHeadPosition() const {
|
||||
return _joint[ AVATAR_JOINT_HEAD_BASE ].position;
|
||||
}
|
||||
|
||||
void Avatar::updateArmIKAndConstraints(float deltaTime) {
|
||||
|
||||
// determine the arm vector
|
||||
|
@ -1170,48 +1130,53 @@ void Avatar::renderBody(bool lookingInMirror) {
|
|||
if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW
|
||||
|| b == AVATAR_JOINT_RIGHT_WRIST
|
||||
|| b == AVATAR_JOINT_RIGHT_FINGERTIPS ) {
|
||||
glColor3f(skinColor[0] + _joint[b].touchForce * 0.3f,
|
||||
skinColor[1] - _joint[b].touchForce * 0.2f,
|
||||
skinColor[2] - _joint[b].touchForce * 0.1f);
|
||||
glColor3f(SKIN_COLOR[0] + _joint[b].touchForce * 0.3f,
|
||||
SKIN_COLOR[1] - _joint[b].touchForce * 0.2f,
|
||||
SKIN_COLOR[2] - _joint[b].touchForce * 0.1f);
|
||||
} else {
|
||||
glColor4f(skinColor[0] + _joint[b].touchForce * 0.3f,
|
||||
skinColor[1] - _joint[b].touchForce * 0.2f,
|
||||
skinColor[2] - _joint[b].touchForce * 0.1f,
|
||||
glColor4f(SKIN_COLOR[0] + _joint[b].touchForce * 0.3f,
|
||||
SKIN_COLOR[1] - _joint[b].touchForce * 0.2f,
|
||||
SKIN_COLOR[2] - _joint[b].touchForce * 0.1f,
|
||||
glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND)
|
||||
/ (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f));
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(_joint[b].springyPosition.x, _joint[b].springyPosition.y, _joint[b].springyPosition.z);
|
||||
glutSolidSphere(_joint[b].radius, 20.0f, 20.0f);
|
||||
glPopMatrix();
|
||||
|
||||
// Render the cone connecting this joint to it's parent
|
||||
|
||||
if (_joint[b].parent != AVATAR_JOINT_NULL)
|
||||
// Render the cone connecting this joint to its parent
|
||||
if (_joint[b].parent != AVATAR_JOINT_NULL) {
|
||||
if ((b != AVATAR_JOINT_HEAD_TOP )
|
||||
&& (b != AVATAR_JOINT_HEAD_BASE )
|
||||
&& (b != AVATAR_JOINT_PELVIS )
|
||||
&& (b != AVATAR_JOINT_TORSO )
|
||||
&& (b != AVATAR_JOINT_CHEST )
|
||||
&& (b != AVATAR_JOINT_LEFT_COLLAR )
|
||||
&& (b != AVATAR_JOINT_LEFT_SHOULDER )
|
||||
&& (b != AVATAR_JOINT_RIGHT_COLLAR )
|
||||
&& (b != AVATAR_JOINT_RIGHT_SHOULDER)) {
|
||||
// Render cone sections connecting the joint positions
|
||||
glColor3fv(darkSkinColor);
|
||||
&& (b != AVATAR_JOINT_HEAD_BASE )
|
||||
&& (b != AVATAR_JOINT_PELVIS )
|
||||
&& (b != AVATAR_JOINT_TORSO )
|
||||
&& (b != AVATAR_JOINT_CHEST )
|
||||
&& (b != AVATAR_JOINT_LEFT_COLLAR )
|
||||
&& (b != AVATAR_JOINT_LEFT_SHOULDER )
|
||||
&& (b != AVATAR_JOINT_RIGHT_COLLAR )
|
||||
&& (b != AVATAR_JOINT_RIGHT_SHOULDER)) {
|
||||
glColor3fv(DARK_SKIN_COLOR);
|
||||
|
||||
float r1 = _joint[_joint[b].parent ].radius * 0.8;
|
||||
float r2 = _joint[b ].radius * 0.8;
|
||||
if (b == AVATAR_JOINT_HEAD_BASE) {
|
||||
r1 *= 0.5f;
|
||||
}
|
||||
renderJointConnectingCone
|
||||
(
|
||||
_joint[_joint[b].parent ].springyPosition,
|
||||
_joint[b ].springyPosition,
|
||||
_joint[_joint[b].parent ].radius * 0.8,
|
||||
_joint[b ].radius * 0.8
|
||||
_joint[b ].springyPosition, r2, r2
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity, float deltaTime, float smoothingTime) {
|
||||
//
|
||||
// Given absolute position and angular velocity information, update the avatar's head angles
|
||||
|
@ -1277,34 +1242,37 @@ void Avatar::readAvatarDataFromFile() {
|
|||
void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2) {
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
int num = 10;
|
||||
|
||||
glm::vec3 axis = glm::normalize(position2 - position1);
|
||||
|
||||
glm::vec3 axis = position2 - position1;
|
||||
float length = glm::length(axis);
|
||||
|
||||
if (length > 0.0f) {
|
||||
|
||||
glm::vec3 perpSin = glm::vec3(axis.y, axis.z, axis.x);
|
||||
glm::vec3 perpCos = glm::vec3(axis.z, axis.x, axis.y);
|
||||
|
||||
float angle1 = 0.0;
|
||||
float angle2 = 0.0;
|
||||
|
||||
for (int i = 0; i < num; i ++) {
|
||||
axis /= length;
|
||||
|
||||
angle1 = angle2;
|
||||
angle2 = ((float)(i+1) / (float)num) * PI * 2.0;
|
||||
glm::vec3 perpSin = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin));
|
||||
perpSin = glm::cross(perpCos, axis);
|
||||
|
||||
float anglea = 0.0;
|
||||
float angleb = 0.0;
|
||||
|
||||
for (int i = 0; i < NUM_BODY_CONE_SIDES; i ++) {
|
||||
|
||||
// the rectangles that comprise the sides of the cone section are
|
||||
// referenced by "a" and "b" in one dimension, and "1", and "2" in the other dimension.
|
||||
anglea = angleb;
|
||||
angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * PI * 2.0f;
|
||||
|
||||
float s1 = sinf(angle1);
|
||||
float s2 = sinf(angle2);
|
||||
float c1 = cosf(angle1);
|
||||
float c2 = cosf(angle2);
|
||||
|
||||
glm::vec3 p1a = position1 + perpSin * s1 * radius1 + perpCos * c1 * radius1;
|
||||
glm::vec3 p1b = position1 + perpSin * s2 * radius1 + perpCos * c2 * radius1;
|
||||
glm::vec3 p2a = position2 + perpSin * s1 * radius2 + perpCos * c1 * radius2;
|
||||
glm::vec3 p2b = position2 + perpSin * s2 * radius2 + perpCos * c2 * radius2;
|
||||
float sa = sinf(anglea);
|
||||
float sb = sinf(angleb);
|
||||
float ca = cosf(anglea);
|
||||
float cb = cosf(angleb);
|
||||
|
||||
glm::vec3 p1a = position1 + perpSin * sa * radius1 + perpCos * ca * radius1;
|
||||
glm::vec3 p1b = position1 + perpSin * sb * radius1 + perpCos * cb * radius1;
|
||||
glm::vec3 p2a = position2 + perpSin * sa * radius2 + perpCos * ca * radius2;
|
||||
glm::vec3 p2b = position2 + perpSin * sb * radius2 + perpCos * cb * radius2;
|
||||
|
||||
glVertex3f(p1a.x, p1a.y, p1a.z);
|
||||
glVertex3f(p1b.x, p1b.y, p1b.z);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// Avatar.h
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 9/11/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
|
@ -19,6 +18,7 @@
|
|||
#include "SerialInterface.h"
|
||||
#include "Balls.h"
|
||||
#include "Head.h"
|
||||
#include "Skeleton.h"
|
||||
#include "Transmitter.h"
|
||||
|
||||
enum DriveKeys
|
||||
|
@ -42,87 +42,52 @@ enum AvatarMode
|
|||
NUM_AVATAR_MODES
|
||||
};
|
||||
|
||||
enum AvatarJointID
|
||||
{
|
||||
AVATAR_JOINT_NULL = -1,
|
||||
AVATAR_JOINT_PELVIS,
|
||||
AVATAR_JOINT_TORSO,
|
||||
AVATAR_JOINT_CHEST,
|
||||
AVATAR_JOINT_NECK_BASE,
|
||||
AVATAR_JOINT_HEAD_BASE,
|
||||
AVATAR_JOINT_HEAD_TOP,
|
||||
AVATAR_JOINT_LEFT_COLLAR,
|
||||
AVATAR_JOINT_LEFT_SHOULDER,
|
||||
AVATAR_JOINT_LEFT_ELBOW,
|
||||
AVATAR_JOINT_LEFT_WRIST,
|
||||
AVATAR_JOINT_LEFT_FINGERTIPS,
|
||||
AVATAR_JOINT_RIGHT_COLLAR,
|
||||
AVATAR_JOINT_RIGHT_SHOULDER,
|
||||
AVATAR_JOINT_RIGHT_ELBOW,
|
||||
AVATAR_JOINT_RIGHT_WRIST,
|
||||
AVATAR_JOINT_RIGHT_FINGERTIPS,
|
||||
AVATAR_JOINT_LEFT_HIP,
|
||||
AVATAR_JOINT_LEFT_KNEE,
|
||||
AVATAR_JOINT_LEFT_HEEL,
|
||||
AVATAR_JOINT_LEFT_TOES,
|
||||
AVATAR_JOINT_RIGHT_HIP,
|
||||
AVATAR_JOINT_RIGHT_KNEE,
|
||||
AVATAR_JOINT_RIGHT_HEEL,
|
||||
AVATAR_JOINT_RIGHT_TOES,
|
||||
|
||||
NUM_AVATAR_JOINTS
|
||||
};
|
||||
|
||||
|
||||
class Avatar : public AvatarData {
|
||||
public:
|
||||
Avatar(Agent* owningAgent = NULL);
|
||||
~Avatar();
|
||||
|
||||
void reset();
|
||||
void updateHeadFromGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity);
|
||||
void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight);
|
||||
void setNoise (float mag) {_head.noise = mag;}
|
||||
float getLastMeasuredHeadYaw() const {return _head.yawRate;}
|
||||
float getBodyYaw() {return _bodyYaw;};
|
||||
void addBodyYaw(float y) {_bodyYaw += y;};
|
||||
void setGravity(glm::vec3 gravity);
|
||||
|
||||
void setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction );
|
||||
bool getIsNearInteractingOther();
|
||||
|
||||
float getAbsoluteHeadYaw() const;
|
||||
float getAbsoluteHeadPitch() const;
|
||||
glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat)
|
||||
const glm::vec3& getHeadPosition() const ; // get the position of the avatar's rigid body head
|
||||
const glm::vec3& getSpringyHeadPosition() const ; // get the springy position of the avatar's head
|
||||
const glm::vec3& getJointPosition(AvatarJointID j) const { return _joint[j].springyPosition; };
|
||||
const glm::vec3& getBodyUpDirection() const { return _orientation.getUp(); };
|
||||
float getSpeed() const { return _speed; }
|
||||
const glm::vec3& getVelocity() const { return _velocity; };
|
||||
float getGirth();
|
||||
float getHeight() const { return _height; }
|
||||
|
||||
AvatarMode getMode() const { return _mode; }
|
||||
Head& getHead() { return _head; }
|
||||
|
||||
void setMousePressed(bool pressed);
|
||||
void render(bool lookingInMirror, glm::vec3 cameraPosition);
|
||||
void renderBody(bool lookingInMirror);
|
||||
void reset();
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
void setMovedHandOffset(glm::vec3 movedHandOffset) { _movedHandOffset = movedHandOffset; }
|
||||
void updateArmIKAndConstraints( float deltaTime );
|
||||
void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors); }
|
||||
|
||||
void updateHeadFromGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity);
|
||||
void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight);
|
||||
void addBodyYaw(float y) {_bodyYaw += y;};
|
||||
void render(bool lookingInMirror, glm::vec3 cameraPosition);
|
||||
|
||||
//setters
|
||||
void setMousePressed (bool mousePressed ) { _mousePressed = mousePressed;}
|
||||
void setNoise (float mag ) { _head.noise = mag;}
|
||||
void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;}
|
||||
void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; };
|
||||
void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);}
|
||||
void setGravity (glm::vec3 gravity);
|
||||
void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction);
|
||||
|
||||
//getters
|
||||
float getHeadYawRate () const { return _head.yawRate;}
|
||||
float getBodyYaw () const { return _bodyYaw;}
|
||||
bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();}
|
||||
const glm::vec3& getHeadPosition () const { return _joint[ AVATAR_JOINT_HEAD_BASE ].position;}
|
||||
const glm::vec3& getSpringyHeadPosition () const { return _joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition;}
|
||||
const glm::vec3& getJointPosition (AvatarJointID j) const { return _joint[j].springyPosition;}
|
||||
const glm::vec3& getBodyUpDirection () const { return _orientation.getUp();}
|
||||
const glm::vec3& getVelocity () const { return _velocity;}
|
||||
float getSpeed () const { return _speed;}
|
||||
float getHeight () const { return _height;}
|
||||
AvatarMode getMode () const { return _mode;}
|
||||
float getAbsoluteHeadYaw () const;
|
||||
float getAbsoluteHeadPitch () const;
|
||||
Head& getHead () {return _head; }
|
||||
|
||||
// Set what driving keys are being pressed to control thrust levels
|
||||
void setDriveKeys(int key, bool val) { _driveKeys[key] = val; };
|
||||
bool getDriveKeys(int key) { return _driveKeys[key]; };
|
||||
|
||||
// Set/Get update the thrust that will move the avatar around
|
||||
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; };
|
||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||
glm::vec3 getThrust() { return _thrust; };
|
||||
|
||||
//read/write avatar data
|
||||
void writeAvatarDataToFile();
|
||||
void readAvatarDataFromFile();
|
||||
|
||||
|
@ -151,6 +116,7 @@ private:
|
|||
};
|
||||
|
||||
Head _head;
|
||||
Skeleton _skeleton;
|
||||
float _TEST_bigSphereRadius;
|
||||
glm::vec3 _TEST_bigSpherePosition;
|
||||
bool _mousePressed;
|
||||
|
@ -184,6 +150,8 @@ private:
|
|||
bool _isMouseTurningRight;
|
||||
|
||||
// private methods...
|
||||
glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat)
|
||||
void renderBody(bool lookingInMirror);
|
||||
void initializeSkeleton();
|
||||
void updateSkeleton();
|
||||
void initializeBodySprings();
|
||||
|
@ -192,6 +160,7 @@ private:
|
|||
void readSensors();
|
||||
void updateHandMovementAndTouching(float deltaTime);
|
||||
void updateAvatarCollisions(float deltaTime);
|
||||
void updateArmIKAndConstraints( float deltaTime );
|
||||
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
|
||||
void updateCollisionWithEnvironment();
|
||||
void updateCollisionWithVoxels();
|
||||
|
|
|
@ -27,55 +27,38 @@ AvatarTouch::AvatarTouch() {
|
|||
_weAreHoldingHands = false;
|
||||
_canReachToOtherAvatar = false;
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
_myOrientation.setToIdentity();
|
||||
_yourOrientation.setToIdentity();
|
||||
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
_point[p] = glm::vec3(0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyHandPosition(glm::vec3 position) {
|
||||
_myHandPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourHandPosition(glm::vec3 position) {
|
||||
_yourHandPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyBodyPosition(glm::vec3 position) {
|
||||
_myBodyPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourBodyPosition(glm::vec3 position) {
|
||||
_yourBodyPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyHandState(int state) {
|
||||
_myHandState = state;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourHandState(int state) {
|
||||
_yourHandState = state;
|
||||
}
|
||||
|
||||
void AvatarTouch::setReachableRadius(float r) {
|
||||
_reachableRadius = r;
|
||||
}
|
||||
|
||||
void AvatarTouch::simulate (float deltaTime) {
|
||||
|
||||
glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition;
|
||||
float distanceBetweenBodies = glm::length(vectorBetweenBodies);
|
||||
glm::vec3 directionBetweenBodies = vectorBetweenBodies / distanceBetweenBodies;
|
||||
|
||||
bool facingEachOther = false;
|
||||
|
||||
if (( glm::dot(_myOrientation.getFront(), _yourOrientation.getFront()) < -0.1f)
|
||||
&& ( glm::dot(_myOrientation.getFront(), directionBetweenBodies ) > 0.1f)) {
|
||||
facingEachOther = true;
|
||||
}
|
||||
|
||||
if (distanceBetweenBodies < _reachableRadius) {
|
||||
if ((distanceBetweenBodies < _reachableRadius)
|
||||
&& (facingEachOther)) {
|
||||
_vectorBetweenHands = _yourHandPosition - _myHandPosition;
|
||||
|
||||
float distanceBetweenHands = glm::length(_vectorBetweenHands);
|
||||
float distanceBetweenHands = glm::length(_vectorBetweenHands);
|
||||
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
|
||||
_handsCloseEnoughToGrasp = true;
|
||||
} else {
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
}
|
||||
|
||||
|
||||
_canReachToOtherAvatar = true;
|
||||
} else {
|
||||
_canReachToOtherAvatar = false;
|
||||
|
@ -92,7 +75,7 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
|
|||
p.y = 0.0005f;
|
||||
renderCircle(p, _reachableRadius, glm::vec3(0.0f, 1.0f, 0.0f), 30);
|
||||
|
||||
// show is we are golding hands...
|
||||
// show if we are holding hands...
|
||||
if (_weAreHoldingHands) {
|
||||
renderBeamBetweenHands();
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define __interface__AvatarTouch__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "Orientation.h"
|
||||
|
||||
enum AvatarHandState
|
||||
{
|
||||
|
@ -26,18 +27,17 @@ public:
|
|||
|
||||
void simulate(float deltaTime);
|
||||
void render(glm::vec3 cameraPosition);
|
||||
|
||||
void setMyHandPosition (glm::vec3 position);
|
||||
void setYourHandPosition(glm::vec3 position);
|
||||
void setMyBodyPosition (glm::vec3 position);
|
||||
void setYourBodyPosition(glm::vec3 position);
|
||||
void setMyHandState (int state);
|
||||
void setYourHandState (int state);
|
||||
void setReachableRadius (float r);
|
||||
|
||||
void setAbleToReachOtherAvatar (bool a) {_canReachToOtherAvatar = a;}
|
||||
void setHandsCloseEnoughToGrasp(bool h) {_handsCloseEnoughToGrasp = h;}
|
||||
void setHoldingHands (bool h) {_weAreHoldingHands = h;}
|
||||
|
||||
void setMyHandPosition (glm::vec3 position ) { _myHandPosition = position; }
|
||||
void setYourHandPosition(glm::vec3 position ) { _yourHandPosition = position; }
|
||||
void setMyOrientation (Orientation orientation) { _myOrientation = orientation; }
|
||||
void setYourOrientation (Orientation orientation) { _yourOrientation = orientation; }
|
||||
void setMyBodyPosition (glm::vec3 position ) { _myBodyPosition = position; }
|
||||
void setYourBodyPosition(glm::vec3 position ) { _yourBodyPosition = position; }
|
||||
void setMyHandState (int state ) { _myHandState = state; }
|
||||
void setYourHandState (int state ) { _yourHandState = state; }
|
||||
void setReachableRadius (float radius ) { _reachableRadius = radius; }
|
||||
void setHoldingHands (bool holding ) { _weAreHoldingHands = holding; }
|
||||
|
||||
bool getAbleToReachOtherAvatar () const {return _canReachToOtherAvatar; }
|
||||
bool getHandsCloseEnoughToGrasp() const {return _handsCloseEnoughToGrasp;}
|
||||
|
@ -47,18 +47,20 @@ private:
|
|||
|
||||
static const int NUM_POINTS = 100;
|
||||
|
||||
bool _weAreHoldingHands;
|
||||
glm::vec3 _point [NUM_POINTS];
|
||||
glm::vec3 _myBodyPosition;
|
||||
glm::vec3 _yourBodyPosition;
|
||||
glm::vec3 _myHandPosition;
|
||||
glm::vec3 _yourHandPosition;
|
||||
glm::vec3 _vectorBetweenHands;
|
||||
int _myHandState;
|
||||
int _yourHandState;
|
||||
bool _canReachToOtherAvatar;
|
||||
bool _handsCloseEnoughToGrasp;
|
||||
float _reachableRadius;
|
||||
bool _weAreHoldingHands;
|
||||
glm::vec3 _point [NUM_POINTS];
|
||||
glm::vec3 _myBodyPosition;
|
||||
glm::vec3 _yourBodyPosition;
|
||||
glm::vec3 _myHandPosition;
|
||||
glm::vec3 _yourHandPosition;
|
||||
Orientation _myOrientation;
|
||||
Orientation _yourOrientation;
|
||||
glm::vec3 _vectorBetweenHands;
|
||||
int _myHandState;
|
||||
int _yourHandState;
|
||||
bool _canReachToOtherAvatar;
|
||||
bool _handsCloseEnoughToGrasp;
|
||||
float _reachableRadius;
|
||||
|
||||
void renderBeamBetweenHands();
|
||||
};
|
||||
|
|
|
@ -11,49 +11,51 @@
|
|||
|
||||
#include "Camera.h"
|
||||
|
||||
const float MODE_SHIFT_RATE = 6.0f;
|
||||
const float CAMERA_MINIMUM_MODE_SHIFT_RATE = 0.5f;
|
||||
|
||||
const float CAMERA_FIRST_PERSON_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_FIRST_PERSON_MODE_DISTANCE = 0.0f;
|
||||
const float CAMERA_FIRST_PERSON_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
const float CAMERA_THIRD_PERSON_MODE_UP_SHIFT = -0.2f;
|
||||
const float CAMERA_THIRD_PERSON_MODE_DISTANCE = 1.5f;
|
||||
const float CAMERA_THIRD_PERSON_MODE_TIGHTNESS = 8.0f;
|
||||
|
||||
const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_MIRROR_MODE_DISTANCE = 0.2f;
|
||||
const float CAMERA_MIRROR_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
Camera::Camera() {
|
||||
|
||||
_needsToInitialize = true;
|
||||
_frustumNeedsReshape = true;
|
||||
|
||||
_modeShift = 0.0;
|
||||
_mode = CAMERA_MODE_THIRD_PERSON;
|
||||
_tightness = 10.0; // default
|
||||
_fieldOfView = 60.0; // default
|
||||
_nearClip = 0.08; // default
|
||||
_farClip = 50.0 * TREE_SCALE; // default
|
||||
_yaw = 0.0;
|
||||
_pitch = 0.0;
|
||||
_roll = 0.0;
|
||||
_upShift = 0.0;
|
||||
_distance = 0.0;
|
||||
_idealYaw = 0.0;
|
||||
_idealPitch = 0.0;
|
||||
_idealRoll = 0.0;
|
||||
_targetPosition = glm::vec3(0.0, 0.0, 0.0);
|
||||
_position = glm::vec3(0.0, 0.0, 0.0);
|
||||
_idealPosition = glm::vec3(0.0, 0.0, 0.0);
|
||||
_modeShift = 0.0f;
|
||||
_modeShiftRate = 1.0f;
|
||||
_linearModeShift = 0.0f;
|
||||
_mode = CAMERA_MODE_THIRD_PERSON;
|
||||
_tightness = 10.0f; // default
|
||||
_fieldOfView = 60.0f; // default
|
||||
_nearClip = 0.08f; // default
|
||||
_farClip = 50.0f * TREE_SCALE; // default
|
||||
_yaw = 0.0f;
|
||||
_pitch = 0.0f;
|
||||
_roll = 0.0f;
|
||||
_upShift = 0.0f;
|
||||
_distance = 0.0f;
|
||||
_previousUpShift = 0.0f;
|
||||
_previousDistance = 0.0f;
|
||||
_previousTightness = 0.0f;
|
||||
_newUpShift = 0.0f;
|
||||
_newDistance = 0.0f;
|
||||
_newTightness = 0.0f;
|
||||
_idealYaw = 0.0f;
|
||||
_idealPitch = 0.0f;
|
||||
_idealRoll = 0.0f;
|
||||
_targetPosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_position = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_idealPosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_orientation.setToIdentity();
|
||||
|
||||
_attributes[CAMERA_MODE_FIRST_PERSON].upShift = CAMERA_DEFAULT_FIRST_PERSON_MODE_UP_SHIFT;
|
||||
_attributes[CAMERA_MODE_FIRST_PERSON].distance = CAMERA_DEFAULT_FIRST_PERSON_MODE_DISTANCE;
|
||||
_attributes[CAMERA_MODE_FIRST_PERSON].tightness = CAMERA_DEFAULT_FIRST_PERSON_MODE_TIGHTNESS;
|
||||
|
||||
_attributes[CAMERA_MODE_THIRD_PERSON].upShift = CAMERA_DEFAULT_THIRD_PERSON_MODE_UP_SHIFT;
|
||||
_attributes[CAMERA_MODE_THIRD_PERSON].distance = CAMERA_DEFAULT_THIRD_PERSON_MODE_DISTANCE;
|
||||
_attributes[CAMERA_MODE_THIRD_PERSON].tightness = CAMERA_DEFAULT_THIRD_PERSON_MODE_TIGHTNESS;
|
||||
|
||||
_attributes[CAMERA_MODE_MIRROR ].upShift = CAMERA_DEFAULT_MIRROR_MODE_UP_SHIFT;
|
||||
_attributes[CAMERA_MODE_MIRROR ].distance = CAMERA_DEFAULT_MIRROR_MODE_DISTANCE;
|
||||
_attributes[CAMERA_MODE_MIRROR ].tightness = CAMERA_DEFAULT_MIRROR_MODE_TIGHTNESS;
|
||||
|
||||
for (int m = 0; m < NUM_CAMERA_MODES; m ++) {
|
||||
_previousAttributes[m].upShift = 0.0f;
|
||||
_previousAttributes[m].distance = 0.0f;
|
||||
_previousAttributes[m].tightness = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::update(float deltaTime) {
|
||||
|
@ -67,7 +69,6 @@ void Camera::update(float deltaTime) {
|
|||
generateOrientation();
|
||||
}
|
||||
|
||||
|
||||
// generate the ortho-normals for the orientation based on the three Euler angles
|
||||
void Camera::generateOrientation() {
|
||||
_orientation.setToIdentity();
|
||||
|
@ -79,15 +80,26 @@ void Camera::generateOrientation() {
|
|||
// use iterative forces to keep the camera at the desired position and angle
|
||||
void Camera::updateFollowMode(float deltaTime) {
|
||||
|
||||
if (_modeShift < 1.0f) {
|
||||
_modeShift += 5.0f * deltaTime;
|
||||
if (_modeShift > 1.0f ) {
|
||||
if (_linearModeShift < 1.0f) {
|
||||
_linearModeShift += _modeShiftRate * deltaTime;
|
||||
|
||||
_modeShift = ONE_HALF - ONE_HALF * cosf(_linearModeShift * PIE );
|
||||
|
||||
_upShift = _previousUpShift * (1.0f - _modeShift) + _newUpShift * _modeShift;
|
||||
_distance = _previousDistance * (1.0f - _modeShift) + _newDistance * _modeShift;
|
||||
_tightness = _previousTightness * (1.0f - _modeShift) + _newTightness * _modeShift;
|
||||
|
||||
if (_linearModeShift > 1.0f ) {
|
||||
_linearModeShift = 1.0f;
|
||||
_modeShift = 1.0f;
|
||||
_upShift = _newUpShift;
|
||||
_distance = _newDistance;
|
||||
_tightness = _newTightness;
|
||||
}
|
||||
}
|
||||
|
||||
// derive t from tightness
|
||||
float t = _tightness * deltaTime;
|
||||
float t = _tightness * _modeShift * deltaTime;
|
||||
if (t > 1.0) {
|
||||
t = 1.0;
|
||||
}
|
||||
|
@ -103,10 +115,6 @@ void Camera::updateFollowMode(float deltaTime) {
|
|||
_pitch += (_idealPitch - _pitch) * t;
|
||||
_roll += (_idealRoll - _roll ) * t;
|
||||
}
|
||||
|
||||
_orientation.yaw (_yaw );
|
||||
_orientation.pitch(_pitch);
|
||||
_orientation.roll (_roll );
|
||||
|
||||
float radian = (_yaw / 180.0) * PIE;
|
||||
|
||||
|
@ -124,32 +132,45 @@ void Camera::updateFollowMode(float deltaTime) {
|
|||
// force position towards ideal position
|
||||
_position += (_idealPosition - _position) * t;
|
||||
}
|
||||
|
||||
float inverseModeShift = 1.0f - _modeShift;
|
||||
_upShift = _attributes[_mode].upShift * _modeShift + _previousAttributes[_mode].upShift * inverseModeShift;
|
||||
_distance = _attributes[_mode].distance * _modeShift + _previousAttributes[_mode].distance * inverseModeShift;
|
||||
_upShift = _attributes[_mode].upShift * _modeShift + _previousAttributes[_mode].upShift * inverseModeShift;
|
||||
}
|
||||
|
||||
|
||||
void Camera::setMode(CameraMode m, CameraFollowingAttributes a) {
|
||||
|
||||
_previousAttributes[m].upShift = _attributes[m].upShift;
|
||||
_previousAttributes[m].distance = _attributes[m].distance;
|
||||
_previousAttributes[m].tightness = _attributes[m].tightness;
|
||||
|
||||
_attributes[m].upShift = a.upShift;
|
||||
_attributes[m].distance = a.distance;
|
||||
_attributes[m].tightness = a.tightness;
|
||||
void Camera::setModeShiftRate ( float rate ) {
|
||||
|
||||
setMode(m);
|
||||
_modeShiftRate = rate;
|
||||
|
||||
if (_modeShiftRate < CAMERA_MINIMUM_MODE_SHIFT_RATE ) {
|
||||
_modeShiftRate = CAMERA_MINIMUM_MODE_SHIFT_RATE;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::setMode(CameraMode m) {
|
||||
void Camera::setMode(CameraMode m) {
|
||||
|
||||
_mode = m;
|
||||
_modeShift = 0.0;
|
||||
_linearModeShift = 0.0;
|
||||
|
||||
_previousUpShift = _upShift;
|
||||
_previousDistance = _distance;
|
||||
_previousTightness = _tightness;
|
||||
|
||||
if (_mode == CAMERA_MODE_THIRD_PERSON) {
|
||||
_newUpShift = CAMERA_THIRD_PERSON_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_THIRD_PERSON_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_THIRD_PERSON_MODE_TIGHTNESS;
|
||||
|
||||
} else if (_mode == CAMERA_MODE_FIRST_PERSON) {
|
||||
_newUpShift = CAMERA_FIRST_PERSON_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_FIRST_PERSON_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_FIRST_PERSON_MODE_TIGHTNESS;
|
||||
|
||||
} else if (_mode == CAMERA_MODE_MIRROR) {
|
||||
_newUpShift = CAMERA_MIRROR_MODE_UP_SHIFT;
|
||||
_newDistance = CAMERA_MIRROR_MODE_DISTANCE;
|
||||
_newTightness = CAMERA_MIRROR_MODE_TIGHTNESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Camera::setTargetRotation( float yaw, float pitch, float roll ) {
|
||||
_idealYaw = yaw;
|
||||
_idealPitch = pitch;
|
||||
|
|
|
@ -21,31 +21,11 @@ enum CameraMode
|
|||
NUM_CAMERA_MODES
|
||||
};
|
||||
|
||||
|
||||
const float CAMERA_DEFAULT_FIRST_PERSON_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_DEFAULT_FIRST_PERSON_MODE_DISTANCE = 0.0f;
|
||||
const float CAMERA_DEFAULT_FIRST_PERSON_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
const float CAMERA_DEFAULT_THIRD_PERSON_MODE_UP_SHIFT = -0.2f;
|
||||
const float CAMERA_DEFAULT_THIRD_PERSON_MODE_DISTANCE = 1.5f;
|
||||
const float CAMERA_DEFAULT_THIRD_PERSON_MODE_TIGHTNESS = 8.0f;
|
||||
|
||||
const float CAMERA_DEFAULT_MIRROR_MODE_UP_SHIFT = 0.0f;
|
||||
const float CAMERA_DEFAULT_MIRROR_MODE_DISTANCE = 0.2f;
|
||||
const float CAMERA_DEFAULT_MIRROR_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
Camera();
|
||||
|
||||
struct CameraFollowingAttributes
|
||||
{
|
||||
float upShift;
|
||||
float distance;
|
||||
float tightness;
|
||||
};
|
||||
|
||||
void initialize(); // instantly put the camera at the ideal position and rotation.
|
||||
|
||||
void update( float deltaTime );
|
||||
|
@ -62,7 +42,7 @@ public:
|
|||
void setTargetRotation( float yaw, float pitch, float roll );
|
||||
|
||||
void setMode ( CameraMode m );
|
||||
void setMode ( CameraMode m, CameraFollowingAttributes attributes );
|
||||
void setModeShiftRate ( float r );
|
||||
void setFieldOfView ( float f );
|
||||
void setAspectRatio ( float a );
|
||||
void setNearClip ( float n );
|
||||
|
@ -102,18 +82,23 @@ private:
|
|||
float _yaw;
|
||||
float _pitch;
|
||||
float _roll;
|
||||
float _upShift;
|
||||
float _idealYaw;
|
||||
float _idealPitch;
|
||||
float _idealRoll;
|
||||
float _upShift;
|
||||
float _distance;
|
||||
float _tightness;
|
||||
float _previousUpShift;
|
||||
float _previousDistance;
|
||||
float _previousTightness;
|
||||
float _newUpShift;
|
||||
float _newDistance;
|
||||
float _newTightness;
|
||||
Orientation _orientation;
|
||||
float _modeShift;
|
||||
float _linearModeShift;
|
||||
float _modeShiftRate;
|
||||
|
||||
CameraFollowingAttributes _attributes[NUM_CAMERA_MODES];
|
||||
CameraFollowingAttributes _previousAttributes[NUM_CAMERA_MODES];
|
||||
|
||||
void generateOrientation();
|
||||
void updateFollowMode( float deltaTime );
|
||||
};
|
||||
|
|
|
@ -13,17 +13,17 @@
|
|||
using namespace std;
|
||||
|
||||
const int MOHAWK_TRIANGLES = 50;
|
||||
const bool USING_PHYSICAL_MOHAWK = true;
|
||||
const float EYE_RIGHT_OFFSET = 0.27f;
|
||||
const float EYE_UP_OFFSET = 0.36f;
|
||||
const float EYE_FRONT_OFFSET = 0.8f;
|
||||
const float EAR_RIGHT_OFFSET = 1.0;
|
||||
const float MOUTH_FRONT_OFFSET = 0.9f;
|
||||
//const float MOUTH_FRONT_OFFSET = 0.9f;
|
||||
const float MOUTH_UP_OFFSET = -0.3f;
|
||||
const float HEAD_MOTION_DECAY = 0.1;
|
||||
const float MINIMUM_EYE_ROTATION_DOT = 0.5f; // based on a dot product: 1.0 is straight ahead, 0.0 is 90 degrees off
|
||||
const float EYEBALL_RADIUS = 0.017;
|
||||
const float EYEBALL_COLOR[3] = { 0.9f, 0.9f, 0.8f };
|
||||
const float HAIR_COLOR[3] = { 0.8f, 0.6f, 0.5f };
|
||||
const float HAIR_SPRING_FORCE = 10.0f;
|
||||
const float HAIR_TORQUE_FORCE = 0.1f;
|
||||
const float HAIR_GRAVITY_FORCE = 0.05f;
|
||||
|
@ -64,26 +64,29 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_mohawkTriangleFan(NULL),
|
||||
_mohawkColors(NULL),
|
||||
_renderLookatVectors(false) {
|
||||
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
_hairTuft[t].length = HAIR_LENGTH;
|
||||
_hairTuft[t].thickness = HAIR_THICKNESS;
|
||||
_hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
_hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_hairTuft[t].midPosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_hairTuft[t].endPosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (USING_PHYSICAL_MOHAWK) {
|
||||
resetHairPhysics();
|
||||
}
|
||||
}
|
||||
|
||||
void Head::reset() {
|
||||
_yaw = _pitch = _roll = 0.0f;
|
||||
_leanForward = _leanSideways = 0.0f;
|
||||
|
||||
if (USING_PHYSICAL_MOHAWK) {
|
||||
resetHairPhysics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Head::resetHairPhysics() {
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
|
||||
_hairTuft[t].length = HAIR_LENGTH;
|
||||
_hairTuft[t].thickness = HAIR_THICKNESS;
|
||||
_hairTuft[t].basePosition = _position + _orientation.getUp() * _scale * 0.9f;
|
||||
_hairTuft[t].midPosition = _hairTuft[t].basePosition + _orientation.getUp() * _hairTuft[t].length * ONE_HALF;
|
||||
_hairTuft[t].endPosition = _hairTuft[t].midPosition + _orientation.getUp() * _hairTuft[t].length * ONE_HALF;
|
||||
|
@ -92,6 +95,7 @@ void Head::reset() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Head::simulate(float deltaTime, bool isMine) {
|
||||
|
||||
const float HEAD_MOTION_DECAY = 0.00;
|
||||
|
@ -140,7 +144,9 @@ void Head::simulate(float deltaTime, bool isMine) {
|
|||
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
|
||||
determineIfLookingAtSomething();
|
||||
|
||||
updateHair(deltaTime);
|
||||
if (USING_PHYSICAL_MOHAWK) {
|
||||
updateHairPhysics(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Head::determineIfLookingAtSomething() {
|
||||
|
@ -195,7 +201,7 @@ void Head::calculateGeometry(bool lookingInMirror) {
|
|||
|
||||
//calculate the mouth position
|
||||
_mouthPosition = _position + _orientation.getUp () * _scale * MOUTH_UP_OFFSET
|
||||
+ _orientation.getFront() * _scale * MOUTH_FRONT_OFFSET;
|
||||
+ _orientation.getFront() * _scale;
|
||||
}
|
||||
|
||||
|
||||
|
@ -206,19 +212,19 @@ void Head::render(bool lookingInMirror, glm::vec3 cameraPosition) {
|
|||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_RESCALE_NORMAL);
|
||||
|
||||
renderMohawk(lookingInMirror);
|
||||
renderMohawk(lookingInMirror, cameraPosition);
|
||||
renderHeadSphere();
|
||||
renderEyeBalls();
|
||||
renderEars();
|
||||
renderMouth();
|
||||
renderEyeBrows();
|
||||
renderHair(cameraPosition);
|
||||
|
||||
if (_renderLookatVectors && _lookingAtSomething) {
|
||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Head::createMohawk() {
|
||||
uint16_t agentId = 0;
|
||||
if (_owningAvatar->getOwningAgent()) {
|
||||
|
@ -250,9 +256,41 @@ void Head::createMohawk() {
|
|||
}
|
||||
}
|
||||
|
||||
void Head::renderMohawk(bool lookingInMirror) {
|
||||
void Head::renderMohawk(bool lookingInMirror, glm::vec3 cameraPosition) {
|
||||
|
||||
if (!_mohawkTriangleFan) {
|
||||
createMohawk();
|
||||
}
|
||||
|
||||
if (USING_PHYSICAL_MOHAWK) {
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
|
||||
glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
|
||||
glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition;
|
||||
glm::vec3 viewVector = _hairTuft[t].basePosition - cameraPosition;
|
||||
|
||||
glm::vec3 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector));
|
||||
glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector));
|
||||
|
||||
glm::vec3 base1 = _hairTuft[t].basePosition - basePerpendicular * _hairTuft[t].thickness * ONE_HALF;
|
||||
glm::vec3 base2 = _hairTuft[t].basePosition + basePerpendicular * _hairTuft[t].thickness * ONE_HALF;
|
||||
glm::vec3 mid1 = _hairTuft[t].midPosition - midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF;
|
||||
glm::vec3 mid2 = _hairTuft[t].midPosition + midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF;
|
||||
|
||||
glColor3f(_mohawkColors[t].x, _mohawkColors[t].y, _mohawkColors[t].z);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex3f(base1.x, base1.y, base1.z );
|
||||
glVertex3f(base2.x, base2.y, base2.z );
|
||||
glVertex3f(mid1.x, mid1.y, mid1.z );
|
||||
glVertex3f(base2.x, base2.y, base2.z );
|
||||
glVertex3f(mid1.x, mid1.y, mid1.z );
|
||||
glVertex3f(mid2.x, mid2.y, mid2.z );
|
||||
glVertex3f(mid1.x, mid1.y, mid1.z );
|
||||
glVertex3f(mid2.x, mid2.y, mid2.z );
|
||||
glVertex3f(_hairTuft[t].endPosition.x, _hairTuft[t].endPosition.y, _hairTuft[t].endPosition.z );
|
||||
glEnd();
|
||||
}
|
||||
} else {
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
|
@ -268,7 +306,7 @@ void Head::renderMohawk(bool lookingInMirror) {
|
|||
}
|
||||
glEnd();
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -304,6 +342,7 @@ void Head::renderMouth() {
|
|||
glm::vec3 u = _orientation.getUp () * _scale * (0.05f + s * 0.0040f );
|
||||
glm::vec3 f = _orientation.getFront() * _scale * 0.09f;
|
||||
|
||||
glm::vec3 middle = _mouthPosition;
|
||||
glm::vec3 leftCorner = _mouthPosition - r * 1.0f;
|
||||
glm::vec3 rightCorner = _mouthPosition + r * 1.0f;
|
||||
glm::vec3 leftTop = _mouthPosition - r * 0.4f + u * 0.7f + f;
|
||||
|
@ -313,6 +352,7 @@ void Head::renderMouth() {
|
|||
|
||||
// constrain all mouth vertices to a sphere slightly larger than the head...
|
||||
float constrainedRadius = _scale + 0.001f;
|
||||
middle = _position + glm::normalize(middle - _position) * constrainedRadius;
|
||||
leftCorner = _position + glm::normalize(leftCorner - _position) * constrainedRadius;
|
||||
rightCorner = _position + glm::normalize(rightCorner - _position) * constrainedRadius;
|
||||
leftTop = _position + glm::normalize(leftTop - _position) * constrainedRadius;
|
||||
|
@ -327,10 +367,16 @@ void Head::renderMouth() {
|
|||
glVertex3f(leftBottom.x, leftBottom.y, leftBottom.z );
|
||||
glVertex3f(leftTop.x, leftTop.y, leftTop.z );
|
||||
glVertex3f(leftTop.x, leftTop.y, leftTop.z );
|
||||
glVertex3f(middle.x, middle.y, middle.z );
|
||||
glVertex3f(rightTop.x, rightTop.y, rightTop.z );
|
||||
glVertex3f(leftTop.x, leftTop.y, leftTop.z );
|
||||
glVertex3f(middle.x, middle.y, middle.z );
|
||||
glVertex3f(leftBottom.x, leftBottom.y, leftBottom.z );
|
||||
glVertex3f(leftBottom.x, leftBottom.y, leftBottom.z );
|
||||
glVertex3f(middle.x, middle.y, middle.z );
|
||||
glVertex3f(rightBottom.x, rightBottom.y, rightBottom.z);
|
||||
glVertex3f(rightTop.x, rightTop.y, rightTop.z );
|
||||
glVertex3f(leftBottom.x, leftBottom.y, leftBottom.z );
|
||||
glVertex3f(middle.x, middle.y, middle.z );
|
||||
glVertex3f(rightBottom.x, rightBottom.y, rightBottom.z);
|
||||
glVertex3f(rightTop.x, rightTop.y, rightTop.z );
|
||||
glVertex3f(rightBottom.x, rightBottom.y, rightBottom.z);
|
||||
|
@ -525,7 +571,7 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi
|
|||
}
|
||||
|
||||
|
||||
void Head::updateHair(float deltaTime) {
|
||||
void Head::updateHairPhysics(float deltaTime) {
|
||||
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
|
||||
|
@ -617,41 +663,3 @@ void Head::updateHair(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Head::renderHair(glm::vec3 cameraPosition) {
|
||||
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
|
||||
glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
|
||||
glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition;
|
||||
glm::vec3 viewVector = _hairTuft[t].basePosition - cameraPosition;
|
||||
|
||||
glm::vec3 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector));
|
||||
glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector));
|
||||
|
||||
glm::vec3 base1 = _hairTuft[t].basePosition - basePerpendicular * _hairTuft[t].thickness * ONE_HALF;
|
||||
glm::vec3 base2 = _hairTuft[t].basePosition + basePerpendicular * _hairTuft[t].thickness * ONE_HALF;
|
||||
glm::vec3 mid1 = _hairTuft[t].midPosition - midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF;
|
||||
glm::vec3 mid2 = _hairTuft[t].midPosition + midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF;
|
||||
|
||||
glColor3fv(HAIR_COLOR);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glVertex3f(base1.x, base1.y, base1.z );
|
||||
glVertex3f(base2.x, base2.y, base2.z );
|
||||
glVertex3f(mid1.x, mid1.y, mid1.z );
|
||||
|
||||
glVertex3f(base2.x, base2.y, base2.z );
|
||||
glVertex3f(mid1.x, mid1.y, mid1.z );
|
||||
glVertex3f(mid2.x, mid2.y, mid2.z );
|
||||
|
||||
glVertex3f(mid1.x, mid1.y, mid1.z );
|
||||
glVertex3f(mid2.x, mid2.y, mid2.z );
|
||||
glVertex3f(_hairTuft[t].endPosition.x, _hairTuft[t].endPosition.y, _hairTuft[t].endPosition.z );
|
||||
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ enum eyeContactTargets
|
|||
};
|
||||
|
||||
const int NUM_HAIR_TUFTS = 4;
|
||||
const int NUM_HAIR_SEGMENTS = 4;
|
||||
|
||||
class Avatar;
|
||||
|
||||
|
@ -36,7 +35,7 @@ public:
|
|||
void reset();
|
||||
void simulate(float deltaTime, bool isMine);
|
||||
void render(bool lookingInMirror, glm::vec3 cameraPosition);
|
||||
void renderMohawk(bool lookingInMirror);
|
||||
void renderMohawk(bool lookingInMirror, glm::vec3 cameraPosition);
|
||||
|
||||
void setScale (float scale ) { _scale = scale; }
|
||||
void setPosition (glm::vec3 position ) { _position = position; }
|
||||
|
@ -108,8 +107,8 @@ private:
|
|||
void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
|
||||
void calculateGeometry( bool lookingInMirror);
|
||||
void determineIfLookingAtSomething();
|
||||
void updateHair(float deltaTime);
|
||||
void renderHair(glm::vec3 cameraPosition);
|
||||
void resetHairPhysics();
|
||||
void updateHairPhysics(float deltaTime);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
20
interface/src/Skeleton.cpp
Normal file
20
interface/src/Skeleton.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Skeleton.cpp
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include "Skeleton.h"
|
||||
|
||||
Skeleton::Skeleton() {
|
||||
}
|
||||
|
||||
void Skeleton::initialize() {
|
||||
}
|
||||
|
||||
void Skeleton::render() {
|
||||
}
|
||||
|
||||
void Skeleton::simulate(float deltaTime) {
|
||||
}
|
||||
|
54
interface/src/Skeleton.h
Normal file
54
interface/src/Skeleton.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Skeleton.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef hifi_Skeleton_h
|
||||
#define hifi_Skeleton_h
|
||||
|
||||
enum AvatarJointID
|
||||
{
|
||||
AVATAR_JOINT_NULL = -1,
|
||||
AVATAR_JOINT_PELVIS,
|
||||
AVATAR_JOINT_TORSO,
|
||||
AVATAR_JOINT_CHEST,
|
||||
AVATAR_JOINT_NECK_BASE,
|
||||
AVATAR_JOINT_HEAD_BASE,
|
||||
AVATAR_JOINT_HEAD_TOP,
|
||||
AVATAR_JOINT_LEFT_COLLAR,
|
||||
AVATAR_JOINT_LEFT_SHOULDER,
|
||||
AVATAR_JOINT_LEFT_ELBOW,
|
||||
AVATAR_JOINT_LEFT_WRIST,
|
||||
AVATAR_JOINT_LEFT_FINGERTIPS,
|
||||
AVATAR_JOINT_RIGHT_COLLAR,
|
||||
AVATAR_JOINT_RIGHT_SHOULDER,
|
||||
AVATAR_JOINT_RIGHT_ELBOW,
|
||||
AVATAR_JOINT_RIGHT_WRIST,
|
||||
AVATAR_JOINT_RIGHT_FINGERTIPS,
|
||||
AVATAR_JOINT_LEFT_HIP,
|
||||
AVATAR_JOINT_LEFT_KNEE,
|
||||
AVATAR_JOINT_LEFT_HEEL,
|
||||
AVATAR_JOINT_LEFT_TOES,
|
||||
AVATAR_JOINT_RIGHT_HIP,
|
||||
AVATAR_JOINT_RIGHT_KNEE,
|
||||
AVATAR_JOINT_RIGHT_HEEL,
|
||||
AVATAR_JOINT_RIGHT_TOES,
|
||||
|
||||
NUM_AVATAR_JOINTS
|
||||
};
|
||||
|
||||
|
||||
class Skeleton {
|
||||
public:
|
||||
Skeleton();
|
||||
|
||||
void initialize();
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue