mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 17:10:45 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into avatardata_optimization
This commit is contained in:
commit
510dfc7353
47 changed files with 2801 additions and 1914 deletions
|
@ -33,6 +33,7 @@ bool includeBillboard = true;
|
|||
bool includeBorderTracer = true;
|
||||
bool includeMovingBug = true;
|
||||
bool includeBlinkingVoxel = false;
|
||||
bool includeDanceFloor = true;
|
||||
|
||||
|
||||
const int ANIMATION_LISTEN_PORT = 40107;
|
||||
|
@ -392,6 +393,131 @@ static void sendBlinkingStringOfLights() {
|
|||
}
|
||||
}
|
||||
|
||||
bool danceFloorInitialized = false;
|
||||
const float DANCE_FLOOR_LIGHT_SIZE = 1.0f / TREE_SCALE; // approximately 1 meter
|
||||
const int DANCE_FLOOR_LENGTH = 10;
|
||||
const int DANCE_FLOOR_WIDTH = 10;
|
||||
glm::vec3 danceFloorPosition(100.0f / TREE_SCALE, 30.0f / TREE_SCALE, 10.0f / TREE_SCALE);
|
||||
glm::vec3 danceFloorLights[DANCE_FLOOR_LENGTH][DANCE_FLOOR_WIDTH];
|
||||
unsigned char danceFloorOffColor[3] = { 240, 240, 240 };
|
||||
const int DANCE_FLOOR_COLORS = 6;
|
||||
|
||||
unsigned char danceFloorOnColorA[DANCE_FLOOR_COLORS][3] = {
|
||||
{ 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 },
|
||||
{ 0, 191, 255 }, { 0, 250, 154 }, { 255, 69, 0 },
|
||||
};
|
||||
unsigned char danceFloorOnColorB[DANCE_FLOOR_COLORS][3] = {
|
||||
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } ,
|
||||
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }
|
||||
};
|
||||
float danceFloorGradient = 0.5f;
|
||||
const float BEATS_PER_MINUTE = 118.0f;
|
||||
const float SECONDS_PER_MINUTE = 60.0f;
|
||||
const float FRAMES_PER_BEAT = (SECONDS_PER_MINUTE * ACTUAL_FPS) / BEATS_PER_MINUTE;
|
||||
float danceFloorGradientIncrement = 1.0f / FRAMES_PER_BEAT;
|
||||
const float DANCE_FLOOR_MAX_GRADIENT = 1.0f;
|
||||
const float DANCE_FLOOR_MIN_GRADIENT = 0.0f;
|
||||
const int DANCE_FLOOR_VOXELS_PER_PACKET = 100;
|
||||
const int PACKETS_PER_DANCE_FLOOR = DANCE_FLOOR_VOXELS_PER_PACKET / (DANCE_FLOOR_WIDTH * DANCE_FLOOR_LENGTH);
|
||||
int danceFloorColors[DANCE_FLOOR_WIDTH][DANCE_FLOOR_LENGTH];
|
||||
|
||||
void sendDanceFloor() {
|
||||
PACKET_HEADER message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; // we're a bully!
|
||||
float lightScale = DANCE_FLOOR_LIGHT_SIZE;
|
||||
static VoxelDetail details[DANCE_FLOOR_VOXELS_PER_PACKET];
|
||||
unsigned char* bufferOut;
|
||||
int sizeOut;
|
||||
|
||||
// first initialized the billboard of lights if needed...
|
||||
if (!::danceFloorInitialized) {
|
||||
for (int i = 0; i < DANCE_FLOOR_WIDTH; i++) {
|
||||
for (int j = 0; j < DANCE_FLOOR_LENGTH; j++) {
|
||||
|
||||
int randomColorIndex = randIntInRange( -(DANCE_FLOOR_COLORS), (DANCE_FLOOR_COLORS + 1));
|
||||
::danceFloorColors[i][j] = randomColorIndex;
|
||||
::danceFloorLights[i][j] = ::danceFloorPosition +
|
||||
glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE);
|
||||
}
|
||||
}
|
||||
::danceFloorInitialized = true;
|
||||
}
|
||||
|
||||
::danceFloorGradient += ::danceFloorGradientIncrement;
|
||||
|
||||
if (::danceFloorGradient >= DANCE_FLOOR_MAX_GRADIENT) {
|
||||
::danceFloorGradient = DANCE_FLOOR_MAX_GRADIENT;
|
||||
::danceFloorGradientIncrement = -::danceFloorGradientIncrement;
|
||||
}
|
||||
if (::danceFloorGradient <= DANCE_FLOOR_MIN_GRADIENT) {
|
||||
::danceFloorGradient = DANCE_FLOOR_MIN_GRADIENT;
|
||||
::danceFloorGradientIncrement = -::danceFloorGradientIncrement;
|
||||
}
|
||||
|
||||
for (int i = 0; i < DANCE_FLOOR_LENGTH; i++) {
|
||||
for (int j = 0; j < DANCE_FLOOR_WIDTH; j++) {
|
||||
|
||||
int nthVoxel = ((i * DANCE_FLOOR_WIDTH) + j);
|
||||
int item = nthVoxel % DANCE_FLOOR_VOXELS_PER_PACKET;
|
||||
|
||||
::danceFloorLights[i][j] = ::danceFloorPosition +
|
||||
glm::vec3(i * DANCE_FLOOR_LIGHT_SIZE, 0, j * DANCE_FLOOR_LIGHT_SIZE);
|
||||
|
||||
details[item].s = lightScale;
|
||||
details[item].x = ::danceFloorLights[i][j].x;
|
||||
details[item].y = ::danceFloorLights[i][j].y;
|
||||
details[item].z = ::danceFloorLights[i][j].z;
|
||||
|
||||
if (danceFloorColors[i][j] > 0) {
|
||||
int color = danceFloorColors[i][j] - 1;
|
||||
details[item].red = (::danceFloorOnColorA[color][0] +
|
||||
((::danceFloorOnColorB[color][0] - ::danceFloorOnColorA[color][0])
|
||||
* ::danceFloorGradient));
|
||||
details[item].green = (::danceFloorOnColorA[color][1] +
|
||||
((::danceFloorOnColorB[color][1] - ::danceFloorOnColorA[color][1])
|
||||
* ::danceFloorGradient));
|
||||
details[item].blue = (::danceFloorOnColorA[color][2] +
|
||||
((::danceFloorOnColorB[color][2] - ::danceFloorOnColorA[color][2])
|
||||
* ::danceFloorGradient));
|
||||
} else if (::danceFloorColors[i][j] < 0) {
|
||||
int color = -(::danceFloorColors[i][j] + 1);
|
||||
details[item].red = (::danceFloorOnColorB[color][0] +
|
||||
((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0])
|
||||
* ::danceFloorGradient));
|
||||
details[item].green = (::danceFloorOnColorB[color][1] +
|
||||
((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1])
|
||||
* ::danceFloorGradient));
|
||||
details[item].blue = (::danceFloorOnColorB[color][2] +
|
||||
((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2])
|
||||
* ::danceFloorGradient));
|
||||
} else {
|
||||
int color = 0;
|
||||
details[item].red = (::danceFloorOnColorB[color][0] +
|
||||
((::danceFloorOnColorA[color][0] - ::danceFloorOnColorB[color][0])
|
||||
* ::danceFloorGradient));
|
||||
details[item].green = (::danceFloorOnColorB[color][1] +
|
||||
((::danceFloorOnColorA[color][1] - ::danceFloorOnColorB[color][1])
|
||||
* ::danceFloorGradient));
|
||||
details[item].blue = (::danceFloorOnColorB[color][2] +
|
||||
((::danceFloorOnColorA[color][2] - ::danceFloorOnColorB[color][2])
|
||||
* ::danceFloorGradient));
|
||||
}
|
||||
|
||||
if (item == DANCE_FLOOR_VOXELS_PER_PACKET - 1) {
|
||||
if (createVoxelEditMessage(message, 0, DANCE_FLOOR_VOXELS_PER_PACKET,
|
||||
(VoxelDetail*)&details, bufferOut, sizeOut)){
|
||||
::packetsSent++;
|
||||
::bytesSent += sizeOut;
|
||||
if (::shouldShowPacketsPerSecond) {
|
||||
printf("sending packet of size=%d\n", sizeOut);
|
||||
}
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool billboardInitialized = false;
|
||||
const int BILLBOARD_HEIGHT = 9;
|
||||
const int BILLBOARD_WIDTH = 45;
|
||||
|
@ -405,7 +531,7 @@ float billboardGradientIncrement = 0.01f;
|
|||
const float BILLBOARD_MAX_GRADIENT = 1.0f;
|
||||
const float BILLBOARD_MIN_GRADIENT = 0.0f;
|
||||
const float BILLBOARD_LIGHT_SIZE = 0.125f / TREE_SCALE; // approximately 1/8 meter per light
|
||||
const int VOXELS_PER_PACKET = 135;
|
||||
const int VOXELS_PER_PACKET = 100;
|
||||
const int PACKETS_PER_BILLBOARD = VOXELS_PER_PACKET / (BILLBOARD_HEIGHT * BILLBOARD_WIDTH);
|
||||
|
||||
|
||||
|
@ -514,6 +640,9 @@ void* animateVoxels(void* args) {
|
|||
if (::includeBlinkingVoxel) {
|
||||
sendVoxelBlinkMessage();
|
||||
}
|
||||
if (::includeDanceFloor) {
|
||||
sendDanceFloor();
|
||||
}
|
||||
|
||||
double end = usecTimestampNow();
|
||||
double elapsedSeconds = (end - ::start) / 1000000.0;
|
||||
|
@ -555,6 +684,9 @@ int main(int argc, const char * argv[])
|
|||
const char* INCLUDE_BLINKING_VOXEL = "--includeBlinkingVoxel";
|
||||
::includeBlinkingVoxel = cmdOptionExists(argc, argv, INCLUDE_BLINKING_VOXEL);
|
||||
|
||||
const char* NO_DANCE_FLOOR = "--NoDanceFloor";
|
||||
::includeDanceFloor = !cmdOptionExists(argc, argv, NO_DANCE_FLOOR);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
const char* showPPS = "--showPPS";
|
||||
::shouldShowPacketsPerSecond = cmdOptionExists(argc, argv, showPPS);
|
||||
|
|
|
@ -55,7 +55,7 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA
|
|||
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
||||
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
|
||||
|
||||
const float DISTANCE_RATIO = 3.0f / 0.3f;
|
||||
const float DISTANCE_SCALE = 2.5f;
|
||||
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
|
||||
const int PHASE_DELAY_AT_90 = 20;
|
||||
|
||||
|
@ -166,8 +166,8 @@ int main(int argc, const char* argv[]) {
|
|||
powf(agentPosition.z - otherAgentPosition.z, 2));
|
||||
|
||||
float minCoefficient = std::min(1.0f,
|
||||
powf(0.5,
|
||||
(logf(DISTANCE_RATIO * distanceToAgent) / logf(2.5))
|
||||
powf(0.3,
|
||||
(logf(DISTANCE_SCALE * distanceToAgent) / logf(2.5))
|
||||
- 1));
|
||||
distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient;
|
||||
}
|
||||
|
@ -214,8 +214,8 @@ int main(int argc, const char* argv[]) {
|
|||
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f));
|
||||
|
||||
attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex]
|
||||
* otherAgentBuffer->getAttenuationRatio()
|
||||
* offAxisCoefficient;
|
||||
* otherAgentBuffer->getAttenuationRatio()
|
||||
* offAxisCoefficient;
|
||||
|
||||
bearingRelativeAngleToSource *= (M_PI / 180);
|
||||
|
||||
|
@ -225,15 +225,15 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
|
||||
int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f
|
||||
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
|
||||
: clientSamples;
|
||||
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
|
||||
: clientSamples;
|
||||
int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f
|
||||
? clientSamples
|
||||
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
? clientSamples
|
||||
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
|
||||
int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
|
||||
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
|
||||
: otherAgentBuffer->getNextOutput() - numSamplesDelay;
|
||||
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
|
||||
: otherAgentBuffer->getNextOutput() - numSamplesDelay;
|
||||
|
||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
|
||||
|
@ -246,7 +246,7 @@ int main(int argc, const char* argv[]) {
|
|||
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient);
|
||||
plateauAdditionOfSamples(goodChannel[s], currentSample);
|
||||
|
||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay],
|
||||
currentSample * weakChannelAmplitudeRatio);
|
||||
}
|
||||
|
@ -287,6 +287,11 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
|
||||
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
|
||||
|
||||
if (std::isnan(((AudioRingBuffer *)avatarAgent->getLinkedData())->getBearing())) {
|
||||
// kill off this agent - temporary solution to mixer crash on mac sleep
|
||||
avatarAgent->setAlive(false);
|
||||
}
|
||||
} else if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) {
|
||||
Agent* matchingInjector = NULL;
|
||||
|
||||
|
|
|
@ -52,9 +52,18 @@ void attachAvatarDataToAgent(Agent* newAgent) {
|
|||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR_MIXER, AVATAR_LISTEN_PORT);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
const char* local = "--local";
|
||||
if (cmdOptionExists(argc, argv, local)) {
|
||||
printf("Local Domain MODE!\n");
|
||||
int ip = getLocalAddress();
|
||||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
agentList->linkedDataCreateCallback = attachAvatarDataToAgent;
|
||||
|
||||
agentList->startDomainServerCheckInThread();
|
||||
|
@ -84,7 +93,7 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
// parse positional data from an agent
|
||||
agentList->updateAgentWithData(avatarAgent, packetData, receivedBytes);
|
||||
|
||||
case PACKET_HEADER_INJECT_AUDIO:
|
||||
currentBufferPosition = broadcastPacket + 1;
|
||||
|
||||
// send back a packet with other active agent data to this agent
|
||||
|
|
|
@ -204,6 +204,4 @@ int main(int argc, const char* argv[]) {
|
|||
agentList->stopDomainServerCheckInThread();
|
||||
agentList->stopPingUnknownAgentsThread();
|
||||
agentList->stopSilentAgentRemovalThread();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,4 +18,5 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
|
|||
# link the shared hifi library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
|
@ -14,14 +14,16 @@
|
|||
#include <string.h>
|
||||
#include <sstream>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <AvatarData.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <UDPSocket.h>
|
||||
#include <AudioInjector.h>
|
||||
#include <AudioInjectionManager.h>
|
||||
|
||||
char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53";
|
||||
const int AUDIO_UDP_LISTEN_PORT = 55443;
|
||||
const int AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15;
|
||||
|
||||
const int DEFAULT_INJECTOR_VOLUME = 0xFF;
|
||||
|
||||
|
@ -30,12 +32,12 @@ bool loopAudio = true;
|
|||
float sleepIntervalMin = 1.00;
|
||||
float sleepIntervalMax = 2.00;
|
||||
char *sourceAudioFile = NULL;
|
||||
const char *allowedParameters = ":rb::t::c::a::f:";
|
||||
const char *allowedParameters = ":rb::t::c::a::f::d:";
|
||||
float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
unsigned char volume = DEFAULT_INJECTOR_VOLUME;
|
||||
float triggerDistance = 0;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
void usage(void) {
|
||||
std::cout << "High Fidelity - Interface audio injector" << std::endl;
|
||||
std::cout << " -r Random sleep mode. If not specified will default to constant loop." << std::endl;
|
||||
std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl;
|
||||
|
@ -43,10 +45,10 @@ void usage(void)
|
|||
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
|
||||
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
|
||||
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
|
||||
std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl;
|
||||
}
|
||||
|
||||
bool processParameters(int parameterCount, char* parameterData[])
|
||||
{
|
||||
bool processParameters(int parameterCount, char* parameterData[]) {
|
||||
int p;
|
||||
while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) {
|
||||
switch (p) {
|
||||
|
@ -86,6 +88,10 @@ bool processParameters(int parameterCount, char* parameterData[])
|
|||
::volume = atoi(optarg);
|
||||
std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl;
|
||||
break;
|
||||
case 'd':
|
||||
::triggerDistance = atof(optarg);
|
||||
std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return false;
|
||||
|
@ -94,45 +100,149 @@ bool processParameters(int parameterCount, char* parameterData[])
|
|||
return true;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
bool stopReceiveAgentDataThread;
|
||||
|
||||
void *receiveAgentData(void *args) {
|
||||
sockaddr senderAddress;
|
||||
ssize_t bytesReceived;
|
||||
unsigned char incomingPacket[MAX_PACKET_SIZE];
|
||||
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
|
||||
while (!::stopReceiveAgentDataThread) {
|
||||
if (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) {
|
||||
switch (incomingPacket[0]) {
|
||||
case PACKET_HEADER_BULK_AVATAR_DATA:
|
||||
// this is the positional data for other agents
|
||||
// pass that off to the agentList processBulkAgentData method
|
||||
agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
break;
|
||||
default:
|
||||
// have the agentList handle list of agents from DS, replies from other agents, etc.
|
||||
agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void createAvatarDataForAgent(Agent* agent) {
|
||||
if (!agent->getLinkedData()) {
|
||||
agent->setLinkedData(new AvatarData(agent));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// new seed for random audio sleep times
|
||||
srand(time(0));
|
||||
|
||||
int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1));
|
||||
|
||||
UDPSocket streamSocket(AUDIO_UDP_SEND_PORT);
|
||||
|
||||
sockaddr_in mixerSocket;
|
||||
mixerSocket.sin_family = AF_INET;
|
||||
mixerSocket.sin_addr.s_addr = inet_addr(EC2_WEST_AUDIO_SERVER);
|
||||
mixerSocket.sin_port = htons((uint16_t)AUDIO_UDP_LISTEN_PORT);
|
||||
|
||||
|
||||
if (processParameters(argc, argv)) {
|
||||
if (processParameters(argc, argv)) {
|
||||
if (::sourceAudioFile == NULL) {
|
||||
std::cout << "[FATAL] Source audio file not specified" << std::endl;
|
||||
exit(-1);
|
||||
} else {
|
||||
AudioInjector injector(sourceAudioFile);
|
||||
|
||||
// create an AgentList instance to handle communication with other agents
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT);
|
||||
|
||||
pthread_t receiveAgentDataThread;
|
||||
pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL);
|
||||
|
||||
// start telling the domain server that we are alive
|
||||
agentList->startDomainServerCheckInThread();
|
||||
|
||||
// start the agent list thread that will kill off agents when they stop talking
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
|
||||
injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2]));
|
||||
injector.setBearing(*(::floatArguments + 3));
|
||||
injector.setVolume(::volume);
|
||||
|
||||
float delay = 0;
|
||||
int usecDelay = 0;
|
||||
|
||||
// register the callback for agent data creation
|
||||
agentList->linkedDataCreateCallback = createAvatarDataForAgent;
|
||||
|
||||
unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO;
|
||||
|
||||
timeval thisSend;
|
||||
double numMicrosecondsSleep = 0;
|
||||
|
||||
while (true) {
|
||||
injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket);
|
||||
|
||||
if (!::loopAudio) {
|
||||
delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax);
|
||||
usecDelay = delay * 1000 * 1000;
|
||||
usleep(usecDelay);
|
||||
if (::triggerDistance) {
|
||||
|
||||
// update the thisSend timeval to the current time
|
||||
gettimeofday(&thisSend, NULL);
|
||||
|
||||
// find the current avatar mixer
|
||||
Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
|
||||
// make sure we actually have an avatar mixer with an active socket
|
||||
if (avatarMixer && avatarMixer->getActiveSocket() != NULL) {
|
||||
// use the UDPSocket instance attached to our agent list to ask avatar mixer for a list of avatars
|
||||
agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(),
|
||||
&broadcastPacket,
|
||||
sizeof(broadcastPacket));
|
||||
}
|
||||
|
||||
if (!injector.isInjectingAudio()) {
|
||||
// enumerate the other agents to decide if one is close enough that we should inject
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
AvatarData* avatarData = (AvatarData*) agent->getLinkedData();
|
||||
|
||||
if (avatarData) {
|
||||
glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition();
|
||||
float squareDistance = glm::dot(tempVector, tempVector);
|
||||
|
||||
if (squareDistance <= ::triggerDistance) {
|
||||
// look for an audio mixer in our agent list
|
||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
|
||||
if (audioMixer) {
|
||||
// we have an active audio mixer we can send data to
|
||||
AudioInjectionManager::threadInjector(&injector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sleep for the correct amount of time to have data send be consistently timed
|
||||
if ((numMicrosecondsSleep = (AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS * 1000) -
|
||||
(usecTimestampNow() - usecTimestamp(&thisSend))) > 0) {
|
||||
usleep(numMicrosecondsSleep);
|
||||
}
|
||||
} else {
|
||||
// look for an audio mixer in our agent list
|
||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
|
||||
if (audioMixer) {
|
||||
injector.injectAudio(agentList->getAgentSocket(), audioMixer->getActiveSocket());
|
||||
}
|
||||
|
||||
float delay = 0;
|
||||
int usecDelay = 0;
|
||||
|
||||
if (!::loopAudio) {
|
||||
delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax);
|
||||
usecDelay = delay * 1000 * 1000;
|
||||
usleep(usecDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stop the receive agent data thread
|
||||
stopReceiveAgentDataThread = true;
|
||||
pthread_join(receiveAgentDataThread, NULL);
|
||||
|
||||
// stop the agent list's threads
|
||||
agentList->stopDomainServerCheckInThread();
|
||||
agentList->stopSilentAgentRemovalThread();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,17 +32,75 @@
|
|||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
uniform vec3 v3LightPos;
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
varying vec3 v3Direction;
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor = gl_Color + fMiePhase * gl_SecondaryColor;
|
||||
gl_FragColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
}
|
||||
|
|
|
@ -1,100 +1,65 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 v3Direction;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = gl_Vertex.xyz;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
gl_FrontSecondaryColor.rgb = v3FrontColor * fKmESun;
|
||||
gl_FrontColor.rgb = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
v3Direction = v3CameraPos - v3Pos;
|
||||
}
|
||||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
position = gl_Vertex.xyz;
|
||||
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
|
|
|
@ -1,48 +1,113 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3LightPos;
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
varying vec3 v3Direction;
|
||||
|
||||
|
||||
void main (void)
|
||||
{
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor = gl_Color + fMiePhase * gl_SecondaryColor;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
}
|
||||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fCameraHeight2; // fCameraHeight^2
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
uniform float fOuterRadius2; // fOuterRadius^2
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
|
||||
float B = 2.0 * dot(v3CameraPos, v3Ray);
|
||||
float C = fCameraHeight2 - fOuterRadius2;
|
||||
float fDet = max(0.0, B*B - 4.0 * C);
|
||||
float fNear = 0.5 * (-B - sqrt(fDet));
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos + v3Ray * fNear;
|
||||
fFar -= fNear;
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
|
||||
float fStartDepth = exp(-1.0 / fScaleDepth);
|
||||
float fStartOffset = fStartDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
vec3 color = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 secondaryColor = v3FrontColor * fKmESun;
|
||||
gl_FragColor.rgb = color + fMiePhase * secondaryColor;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
}
|
||||
|
|
|
@ -1,109 +1,41 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fCameraHeight2; // fCameraHeight^2
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
uniform float fOuterRadius2; // fOuterRadius^2
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 v3Direction;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = gl_Vertex.xyz;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
|
||||
float B = 2.0 * dot(v3CameraPos, v3Ray);
|
||||
float C = fCameraHeight2 - fOuterRadius2;
|
||||
float fDet = max(0.0, B*B - 4.0 * C);
|
||||
float fNear = 0.5 * (-B - sqrt(fDet));
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos + v3Ray * fNear;
|
||||
fFar -= fNear;
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
|
||||
float fStartDepth = exp(-1.0 / fScaleDepth);
|
||||
float fStartOffset = fStartDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
gl_FrontSecondaryColor.rgb = v3FrontColor * fKmESun;
|
||||
gl_FrontColor.rgb = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
v3Direction = v3CameraPos - v3Pos;
|
||||
}
|
||||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
position = gl_Vertex.xyz;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const bool TESTING_AVATAR_TOUCH = false;
|
||||
|
||||
// Starfield information
|
||||
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
||||
static char STAR_CACHE_FILE[] = "cachedStars.txt";
|
||||
|
@ -254,8 +256,6 @@ void Application::initializeGL() {
|
|||
printLog("Network receive thread created.\n");
|
||||
}
|
||||
|
||||
_myAvatar.readAvatarDataFromFile();
|
||||
|
||||
// call terminate before exiting
|
||||
connect(this, SIGNAL(aboutToQuit()), SLOT(terminate()));
|
||||
|
||||
|
@ -269,6 +269,8 @@ void Application::initializeGL() {
|
|||
connect(idleTimer, SIGNAL(timeout()), SLOT(idle()));
|
||||
idleTimer->start(0);
|
||||
|
||||
readSettings();
|
||||
|
||||
if (_justStarted) {
|
||||
float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime))/1000000.0;
|
||||
_justStarted = false;
|
||||
|
@ -287,34 +289,23 @@ void Application::paintGL() {
|
|||
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
_myCamera.setTightness (100.0f);
|
||||
_myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar.getBodyYaw() - 180.0f,
|
||||
0.0f,
|
||||
0.0f);
|
||||
_myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE));
|
||||
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
|
||||
|
||||
} else if (OculusManager::isConnected()) {
|
||||
_myCamera.setUpShift (0.0f);
|
||||
_myCamera.setDistance (0.0f);
|
||||
_myCamera.setTightness (100.0f);
|
||||
_myCamera.setTargetPosition(_myAvatar.getHeadPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(),
|
||||
_myAvatar.getHead().getPitch(),
|
||||
-_myAvatar.getHead().getRoll());
|
||||
_myCamera.setTargetPosition(_myAvatar.getHeadJointPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar.getHead().getOrientation());
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(),
|
||||
_myAvatar.getAbsoluteHeadPitch(),
|
||||
0.0f);
|
||||
// Take a look at whether we are inside head, don't render it if so.
|
||||
const float HEAD_RENDER_DISTANCE = 0.5;
|
||||
glm::vec3 distanceToHead(_myCamera.getPosition() - _myAvatar.getSpringyHeadPosition());
|
||||
_myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE));
|
||||
_myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation());
|
||||
|
||||
if (glm::length(distanceToHead) < HEAD_RENDER_DISTANCE) {
|
||||
}
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
_myCamera.setTargetPosition(_myAvatar.getHeadPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(),
|
||||
_myAvatar.getAbsoluteHeadPitch(),
|
||||
0.0f);
|
||||
_myCamera.setTargetPosition(_myAvatar.getHeadJointPosition());
|
||||
_myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation());
|
||||
}
|
||||
|
||||
// important...
|
||||
|
@ -344,11 +335,12 @@ void Application::paintGL() {
|
|||
if (_viewFrustumFromOffset->isChecked() && _frustumOn->isChecked()) {
|
||||
|
||||
// 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.setTargetPosition(_myCamera.getTargetPosition());
|
||||
_viewFrustumOffsetCamera.setTargetRotation(_myCamera.getTargetRotation() * glm::quat(glm::radians(glm::vec3(
|
||||
_viewFrustumOffsetPitch, _viewFrustumOffsetYaw, _viewFrustumOffsetRoll))));
|
||||
_viewFrustumOffsetCamera.setUpShift (_viewFrustumOffsetUp );
|
||||
_viewFrustumOffsetCamera.setDistance (_viewFrustumOffsetDistance);
|
||||
_viewFrustumOffsetCamera.initialize(); // force immediate snap to ideal position and orientation
|
||||
_viewFrustumOffsetCamera.update(1.f/_fps);
|
||||
whichCamera = _viewFrustumOffsetCamera;
|
||||
}
|
||||
|
@ -733,7 +725,178 @@ void Application::wheelEvent(QWheelEvent* event) {
|
|||
decreaseVoxelSize();
|
||||
}
|
||||
}
|
||||
|
||||
const char AVATAR_DATA_FILENAME[] = "avatar.ifd";
|
||||
|
||||
void Application::readSettingsFile() {
|
||||
FILE* settingsFile = fopen(AVATAR_DATA_FILENAME, "rt");
|
||||
|
||||
if (settingsFile) {
|
||||
char line[LINE_MAX];
|
||||
|
||||
while (fgets(line, LINE_MAX, settingsFile) != NULL)
|
||||
{
|
||||
if (strcmp(line, " \n") > 0) {
|
||||
char* token = NULL;
|
||||
char* settingLine = NULL;
|
||||
char* toFree = NULL;
|
||||
|
||||
settingLine = strdup(line);
|
||||
|
||||
if (settingLine != NULL) {
|
||||
toFree = settingLine;
|
||||
|
||||
int i = 0;
|
||||
|
||||
char key[128];
|
||||
char value[128];
|
||||
|
||||
|
||||
while ((token = strsep(&settingLine, "=")) != NULL)
|
||||
{
|
||||
switch (i) {
|
||||
case 0:
|
||||
strcpy(key, token);
|
||||
_settingsTable[key] = "";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
strcpy(value, token);
|
||||
_settingsTable[key] = token;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
free(toFree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(settingsFile);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::saveSettingsFile() {
|
||||
FILE* settingsFile = fopen(AVATAR_DATA_FILENAME, "wt");
|
||||
|
||||
if (settingsFile) {
|
||||
for (std::map<std::string, std::string>::iterator i = _settingsTable.begin(); i != _settingsTable.end(); i++)
|
||||
{
|
||||
fprintf(settingsFile, "\n%s=%s", i->first.data(), i->second.data());
|
||||
}
|
||||
}
|
||||
|
||||
fclose(settingsFile);
|
||||
}
|
||||
|
||||
bool Application::getSetting(const char* setting, bool& value, const bool defaultSetting) const {
|
||||
std::map<std::string, std::string>::const_iterator iter = _settingsTable.find(setting);
|
||||
|
||||
if (iter != _settingsTable.end()) {
|
||||
int readBool;
|
||||
|
||||
int res = sscanf(iter->second.data(), "%d", &readBool);
|
||||
|
||||
const char EXPECTED_ITEMS = 1;
|
||||
|
||||
if (res == EXPECTED_ITEMS) {
|
||||
if (readBool == 1) {
|
||||
value = true;
|
||||
} else if (readBool == 0) {
|
||||
value = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::getSetting(const char* setting, float& value, const float defaultSetting) const {
|
||||
std::map<std::string, std::string>::const_iterator iter = _settingsTable.find(setting);
|
||||
|
||||
if (iter != _settingsTable.end()) {
|
||||
float readFloat;
|
||||
|
||||
int res = sscanf(iter->second.data(), "%f", &readFloat);
|
||||
|
||||
const char EXPECTED_ITEMS = 1;
|
||||
|
||||
if (res == EXPECTED_ITEMS) {
|
||||
if (!isnan(readFloat)) {
|
||||
value = readFloat;
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::getSetting(const char* setting, glm::vec3& value, const glm::vec3& defaultSetting) const {
|
||||
std::map<std::string, std::string>::const_iterator iter = _settingsTable.find(setting);
|
||||
|
||||
if (iter != _settingsTable.end()) {
|
||||
glm::vec3 readVec;
|
||||
|
||||
int res = sscanf(iter->second.data(), "%f,%f,%f", &readVec.x, &readVec.y, &readVec.z);
|
||||
|
||||
const char EXPECTED_ITEMS = 3;
|
||||
|
||||
if (res == EXPECTED_ITEMS) {
|
||||
if (!isnan(readVec.x) && !isnan(readVec.y) && !isnan(readVec.z)) {
|
||||
value = readVec;
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
value = defaultSetting;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const short MAX_SETTINGS_LENGTH = 128;
|
||||
|
||||
void Application::setSetting(const char* setting, const bool value) {
|
||||
char settingValues[MAX_SETTINGS_LENGTH];
|
||||
sprintf(settingValues, "%d", value);
|
||||
_settingsTable[setting] = settingValues;
|
||||
}
|
||||
|
||||
void Application::setSetting(const char* setting, const float value) {
|
||||
char settingValues[MAX_SETTINGS_LENGTH];
|
||||
sprintf(settingValues, "%f", value);
|
||||
_settingsTable[setting] = settingValues;
|
||||
}
|
||||
|
||||
void Application::setSetting(const char* setting, const glm::vec3& value) {
|
||||
char settingValues[MAX_SETTINGS_LENGTH];
|
||||
sprintf(settingValues, "%f,%f,%f", value.x, value.y, value.z);
|
||||
_settingsTable[setting] = settingValues;
|
||||
}
|
||||
|
||||
// Every second, check the frame rates and other stuff
|
||||
void Application::timer() {
|
||||
gettimeofday(&_timerEnd, NULL);
|
||||
|
@ -887,6 +1050,8 @@ void Application::idle() {
|
|||
_serialPort.readData(deltaTime);
|
||||
}
|
||||
|
||||
// Update transmitter
|
||||
|
||||
// Sample hardware, update view frustum if needed, and send avatar data to mixer/agents
|
||||
updateAvatar(deltaTime);
|
||||
|
||||
|
@ -901,7 +1066,7 @@ void Application::idle() {
|
|||
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL) {
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
avatar->simulate(deltaTime, false);
|
||||
avatar->simulate(deltaTime, NULL);
|
||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
}
|
||||
}
|
||||
|
@ -915,39 +1080,34 @@ void Application::idle() {
|
|||
_myAvatar.simulate(deltaTime, NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
if (TESTING_AVATAR_TOUCH) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
} else {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) {
|
||||
if (_manualFirstPerson) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) {
|
||||
_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);
|
||||
} else {
|
||||
if (_myAvatar.getIsNearInteractingOther()) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
} else {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update audio stats for procedural sounds
|
||||
#ifndef _WIN32
|
||||
_audio.setLastAcceleration(_myAvatar.getThrust());
|
||||
|
@ -963,7 +1123,7 @@ void Application::terminate() {
|
|||
// Close serial port
|
||||
// close(serial_fd);
|
||||
|
||||
_myAvatar.writeAvatarDataToFile();
|
||||
saveSettings();
|
||||
|
||||
if (_enableNetworkThread) {
|
||||
_stopNetworkReceiveThread = true;
|
||||
|
@ -975,23 +1135,13 @@ void Application::pair() {
|
|||
PairingHandler::sendPairRequest();
|
||||
}
|
||||
|
||||
void Application::setHead(bool head) {
|
||||
#ifndef _WIN32
|
||||
_audio.setMixerLoopbackFlag(head);
|
||||
#endif
|
||||
|
||||
void Application::setHead(bool head) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1142,13 +1292,15 @@ void Application::initMenu() {
|
|||
_window->setMenuBar(menuBar);
|
||||
|
||||
QMenu* fileMenu = menuBar->addMenu("File");
|
||||
fileMenu->addAction("Quit", this, SLOT(quit()), Qt::Key_Q);
|
||||
fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q);
|
||||
|
||||
QMenu* pairMenu = menuBar->addMenu("Pair");
|
||||
pairMenu->addAction("Pair", this, SLOT(pair()));
|
||||
|
||||
QMenu* optionsMenu = menuBar->addMenu("Options");
|
||||
(_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setHead(bool)), Qt::Key_H))->setCheckable(true);
|
||||
(_echoAudioMode = optionsMenu->addAction("Echo Audio"))->setCheckable(true);
|
||||
|
||||
optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N)->setCheckable(true);
|
||||
(_gyroLook = optionsMenu->addAction("Gyro Look"))->setCheckable(true);
|
||||
_gyroLook->setChecked(true);
|
||||
|
@ -1285,11 +1437,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);
|
||||
|
@ -1305,7 +1454,7 @@ void Application::init() {
|
|||
|
||||
void Application::updateAvatar(float deltaTime) {
|
||||
// Update my avatar's head position from gyros
|
||||
_myAvatar.updateHeadFromGyros(deltaTime, &_serialPort, &_gravity);
|
||||
_myAvatar.updateHeadFromGyros(deltaTime, &_serialPort);
|
||||
|
||||
// Grab latest readings from the gyros
|
||||
float measuredPitchRate = _serialPort.getLastPitchRate();
|
||||
|
@ -1336,7 +1485,7 @@ void Application::updateAvatar(float deltaTime) {
|
|||
|
||||
// Get audio loudness data from audio input device
|
||||
#ifndef _WIN32
|
||||
_myAvatar.setLoudness(_audio.getLastInputLoudness());
|
||||
_myAvatar.getHead().setAudioLoudness(_audio.getLastInputLoudness());
|
||||
#endif
|
||||
|
||||
// Update Avatar with latest camera and view frustum data...
|
||||
|
@ -1398,27 +1547,22 @@ void Application::updateAvatar(float deltaTime) {
|
|||
void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
|
||||
// We will use these below, from either the camera or head vectors calculated above
|
||||
glm::vec3 position;
|
||||
glm::vec3 direction;
|
||||
glm::vec3 up;
|
||||
glm::vec3 right;
|
||||
float fov, nearClip, farClip;
|
||||
|
||||
// Camera or Head?
|
||||
if (_cameraFrustum->isChecked()) {
|
||||
position = camera.getPosition();
|
||||
} else {
|
||||
position = _myAvatar.getHeadPosition();
|
||||
position = _myAvatar.getHeadJointPosition();
|
||||
}
|
||||
|
||||
fov = camera.getFieldOfView();
|
||||
nearClip = camera.getNearClip();
|
||||
farClip = camera.getFarClip();
|
||||
float fov = camera.getFieldOfView();
|
||||
float nearClip = camera.getNearClip();
|
||||
float farClip = camera.getFarClip();
|
||||
|
||||
Orientation o = camera.getOrientation();
|
||||
|
||||
direction = o.getFront();
|
||||
up = o.getUp();
|
||||
right = o.getRight();
|
||||
glm::quat rotation = camera.getRotation();
|
||||
glm::vec3 direction = rotation * AVATAR_FRONT;
|
||||
glm::vec3 up = rotation * AVATAR_UP;
|
||||
glm::vec3 right = rotation * AVATAR_RIGHT;
|
||||
|
||||
/*
|
||||
printf("position.x=%f, position.y=%f, position.z=%f\n", position.x, position.y, position.z);
|
||||
|
@ -1604,11 +1748,10 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
// 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(), 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 );
|
||||
glm::quat rotation = whichCamera.getRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(-glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
|
||||
glTranslatef(-whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z);
|
||||
|
||||
|
@ -1667,7 +1810,6 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
glPopMatrix();
|
||||
|
||||
//draw a grid ground plane....
|
||||
const float EDGE_SIZE_GROUND_PLANE = 20.f;
|
||||
drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE);
|
||||
|
||||
// Draw voxels
|
||||
|
@ -1703,13 +1845,13 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
avatar->render(false, _myCamera.getPosition());
|
||||
avatar->render(false);
|
||||
}
|
||||
}
|
||||
agentList->unlock();
|
||||
|
||||
// Render my own Avatar
|
||||
_myAvatar.render(_lookingInMirror->isChecked(), _myCamera.getPosition());
|
||||
_myAvatar.render(_lookingInMirror->isChecked());
|
||||
_myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked());
|
||||
}
|
||||
|
||||
|
@ -2220,3 +2362,95 @@ void* Application::networkReceive(void* args) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void Application::saveSettings()
|
||||
{
|
||||
// Handle any persistent settings saving here when we get a call to terminate.
|
||||
// This should probably be moved to a map stored in memory at some point to cache settings.
|
||||
_myAvatar.writeAvatarDataToFile();
|
||||
|
||||
setSetting("_gyroLook", _gyroLook->isChecked());
|
||||
|
||||
setSetting("_mouseLook", _mouseLook->isChecked());
|
||||
|
||||
setSetting("_transmitterDrives", _transmitterDrives->isChecked());
|
||||
|
||||
setSetting("_renderVoxels", _renderVoxels->isChecked());
|
||||
|
||||
setSetting("_renderVoxelTextures", _renderVoxelTextures->isChecked());
|
||||
|
||||
setSetting("_renderStarsOn", _renderStarsOn->isChecked());
|
||||
|
||||
setSetting("_renderAtmosphereOn", _renderAtmosphereOn->isChecked());
|
||||
|
||||
setSetting("_renderAvatarsOn", _renderAvatarsOn->isChecked());
|
||||
|
||||
setSetting("_renderStatsOn", _renderStatsOn->isChecked());
|
||||
|
||||
setSetting("_renderFrameTimerOn", _renderFrameTimerOn->isChecked());
|
||||
|
||||
setSetting("_renderLookatOn", _renderLookatOn->isChecked());
|
||||
|
||||
setSetting("_logOn", _logOn->isChecked());
|
||||
|
||||
setSetting("_frustumOn", _frustumOn->isChecked());
|
||||
|
||||
setSetting("_viewFrustumFromOffset", _viewFrustumFromOffset->isChecked());
|
||||
|
||||
setSetting("_cameraFrustum", _cameraFrustum->isChecked());
|
||||
|
||||
saveSettingsFile();
|
||||
}
|
||||
|
||||
void Application::readSettings()
|
||||
{
|
||||
readSettingsFile();
|
||||
_myAvatar.readAvatarDataFromFile();
|
||||
|
||||
bool settingState;
|
||||
getSetting("_gyroLook", settingState, _gyroLook->isChecked());
|
||||
_gyroLook->setChecked(settingState);
|
||||
|
||||
getSetting("_mouseLook", settingState, _mouseLook->isChecked());
|
||||
_mouseLook->setChecked(settingState);
|
||||
|
||||
getSetting("_transmitterDrives", settingState, _transmitterDrives->isChecked());
|
||||
_transmitterDrives->setChecked(settingState);
|
||||
|
||||
getSetting("_renderVoxels", settingState, _renderVoxels->isChecked());
|
||||
_renderVoxels->setChecked(settingState);
|
||||
|
||||
getSetting("_renderVoxelTextures", settingState, _renderVoxelTextures->isChecked());
|
||||
_renderVoxelTextures->setChecked(settingState);
|
||||
|
||||
getSetting("_renderStarsOn", settingState, _renderStarsOn->isChecked());
|
||||
_renderStarsOn->setChecked(settingState);
|
||||
|
||||
getSetting("_renderAtmosphereOn", settingState, _renderAtmosphereOn->isChecked());
|
||||
_renderAtmosphereOn->setChecked(settingState);
|
||||
|
||||
getSetting("_renderAvatarsOn", settingState, _renderAvatarsOn->isChecked());
|
||||
_renderAvatarsOn->setChecked(settingState);
|
||||
|
||||
getSetting("_renderStatsOn", settingState, _renderStatsOn->isChecked());
|
||||
_renderStatsOn->setChecked(settingState);
|
||||
|
||||
getSetting("_renderFrameTimerOn", settingState, _renderFrameTimerOn->isChecked());
|
||||
_renderFrameTimerOn->setChecked(settingState);
|
||||
|
||||
getSetting("_renderLookatOn", settingState, _renderLookatOn->isChecked());
|
||||
_renderLookatOn->setChecked(settingState);
|
||||
|
||||
getSetting("_logOn", settingState, _logOn->isChecked());
|
||||
_logOn->setChecked(settingState);
|
||||
|
||||
getSetting("_frustumOn", settingState, _frustumOn->isChecked());
|
||||
_frustumOn->setChecked(settingState);
|
||||
|
||||
getSetting("_viewFrustumFromOffset", settingState, _viewFrustumFromOffset->isChecked());
|
||||
_viewFrustumFromOffset->setChecked(settingState);
|
||||
|
||||
getSetting("_cameraFrustum", settingState, _cameraFrustum->isChecked());
|
||||
_cameraFrustum->setChecked(settingState);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <map>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
|
||||
#include <AgentList.h>
|
||||
|
||||
|
@ -62,8 +64,61 @@ public:
|
|||
void wheelEvent(QWheelEvent* event);
|
||||
|
||||
Avatar* getAvatar() { return &_myAvatar; }
|
||||
Camera* getCamera() { return &_myCamera; }
|
||||
VoxelSystem* getVoxels() { return &_voxels; }
|
||||
Environment* getEnvironment() { return &_environment; }
|
||||
bool shouldEchoAudio() { return _echoAudioMode->isChecked(); }
|
||||
|
||||
/*!
|
||||
@fn getSettingBool
|
||||
@brief A function for getting boolean settings from the settings file.
|
||||
@param settingName The desired setting to get the value for.
|
||||
@param boolSetting The referenced variable where the setting will be stored.
|
||||
@param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to false.
|
||||
*/
|
||||
bool getSetting(const char* setting, bool &value, const bool defaultSetting = false) const;
|
||||
|
||||
/*!
|
||||
@fn getSettingFloat
|
||||
@brief A function for getting float settings from the settings file.
|
||||
@param settingName The desired setting to get the value for.
|
||||
@param floatSetting The referenced variable where the setting will be stored.
|
||||
@param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to 0.0f.
|
||||
*/
|
||||
bool getSetting(const char* setting, float &value, const float defaultSetting = 0.0f) const;
|
||||
|
||||
/*!
|
||||
@fn getSettingVec3
|
||||
@brief A function for getting boolean settings from the settings file.
|
||||
@param settingName The desired setting to get the value for.
|
||||
@param vecSetting The referenced variable where the setting will be stored.
|
||||
@param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to <0.0f, 0.0f, 0.0f>
|
||||
*/
|
||||
bool getSetting(const char* setting, glm::vec3 &value, const glm::vec3& defaultSetting = glm::vec3(0.0f, 0.0f, 0.0f)) const;
|
||||
|
||||
/*!
|
||||
@fn setSettingBool
|
||||
@brief A function for setting boolean setting values when saving the settings file.
|
||||
@param settingName The desired setting to populate a value for.
|
||||
@param boolSetting The value to set.
|
||||
*/
|
||||
void setSetting(const char* setting, const bool value);
|
||||
|
||||
/*!
|
||||
@fn setSettingFloat
|
||||
@brief A function for setting boolean setting values when saving the settings file.
|
||||
@param settingName The desired setting to populate a value for.
|
||||
@param floatSetting The value to set.
|
||||
*/
|
||||
void setSetting(const char* setting, const float value);
|
||||
|
||||
/*!
|
||||
@fn setSettingVec3
|
||||
@brief A function for setting boolean setting values when saving the settings file.
|
||||
@param settingName The desired setting to populate a value for.
|
||||
@param vecSetting The value to set.
|
||||
*/
|
||||
void setSetting(const char* setting, const glm::vec3& value);
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -134,10 +189,18 @@ private:
|
|||
static void attachNewHeadToAgent(Agent *newAgent);
|
||||
static void* networkReceive(void* args);
|
||||
|
||||
// These two functions are technically not necessary, but they help keep things in one place.
|
||||
void readSettings(); //! This function is largely to help consolidate getting settings in one place.
|
||||
void saveSettings(); //! This function is to consolidate any settings setting in one place.
|
||||
|
||||
void readSettingsFile(); //! This function reads data from the settings file, splitting data into key value pairs using '=' as a delimiter.
|
||||
void saveSettingsFile(); //! This function writes all changes in the settings table to the settings file, serializing all settings added through the setSetting functions.
|
||||
|
||||
QMainWindow* _window;
|
||||
QGLWidget* _glWidget;
|
||||
|
||||
QAction* _lookingInMirror; // Are we currently rendering one's own head as if in mirror?
|
||||
QAction* _lookingInMirror; // Are we currently rendering one's own head as if in mirror?
|
||||
QAction* _echoAudioMode; // Are we asking the mixer to echo back our audio?
|
||||
QAction* _gyroLook; // Whether to allow the gyro data from head to move your view
|
||||
QAction* _mouseLook; // Whether the have the mouse near edge of screen move your view
|
||||
QAction* _showHeadMouse; // Whether the have the mouse near edge of screen move your view
|
||||
|
@ -251,6 +314,12 @@ private:
|
|||
int _packetsPerSecond;
|
||||
int _bytesPerSecond;
|
||||
int _bytesCount;
|
||||
|
||||
/*!
|
||||
* Store settings in a map, storing keys and values as strings.
|
||||
* Interpret values as needed on demand. through the appropriate getters and setters.
|
||||
*/
|
||||
std::map<std::string, std::string> _settingsTable;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__Application__) */
|
||||
|
|
|
@ -116,7 +116,7 @@ int audioCallback (const void* inputBuffer,
|
|||
printLog("got output\n");
|
||||
}
|
||||
|
||||
if (inputLeft != NULL) {
|
||||
if (agentList && inputLeft) {
|
||||
|
||||
// Measure the loudness of the signal from the microphone and store in audio object
|
||||
float loudness = 0;
|
||||
|
@ -143,7 +143,7 @@ int audioCallback (const void* inputBuffer,
|
|||
unsigned char *currentPacketPtr = dataPacket + 1;
|
||||
|
||||
// memcpy the three float positions
|
||||
memcpy(currentPacketPtr, &interfaceAvatar->getHeadPosition(), sizeof(float) * 3);
|
||||
memcpy(currentPacketPtr, &interfaceAvatar->getHeadJointPosition(), sizeof(float) * 3);
|
||||
currentPacketPtr += (sizeof(float) * 3);
|
||||
|
||||
// tell the mixer not to add additional attenuation to our source
|
||||
|
@ -158,10 +158,10 @@ int audioCallback (const void* inputBuffer,
|
|||
correctedYaw += 360;
|
||||
}
|
||||
|
||||
if (parentAudio->_mixerLoopbackFlag) {
|
||||
if (Application::getInstance()->shouldEchoAudio()) {
|
||||
correctedYaw = correctedYaw > 0
|
||||
? correctedYaw + AGENT_LOOPBACK_MODIFIER
|
||||
: correctedYaw - AGENT_LOOPBACK_MODIFIER;
|
||||
? correctedYaw + AGENT_LOOPBACK_MODIFIER
|
||||
: correctedYaw - AGENT_LOOPBACK_MODIFIER;
|
||||
}
|
||||
|
||||
memcpy(currentPacketPtr, &correctedYaw, sizeof(float));
|
||||
|
@ -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
|
||||
|
@ -310,7 +310,6 @@ Audio::Audio(Oscilloscope* scope) :
|
|||
NUM_AUDIO_CHANNELS * (SAMPLE_RATE / 1000.0)),
|
||||
_wasStarved(0),
|
||||
_lastInputLoudness(0),
|
||||
_mixerLoopbackFlag(false),
|
||||
_lastVelocity(0),
|
||||
_lastAcceleration(0),
|
||||
_totalPacketsReceived(0),
|
||||
|
@ -457,7 +456,7 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy
|
|||
gettimeofday(&_firstPlaybackTime, NULL);
|
||||
}
|
||||
|
||||
_ringBuffer.parseData((unsigned char *)receivedData, PACKET_LENGTH_BYTES);
|
||||
_ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||
|
||||
_lastReceiveTime = currentReceiveTime;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ public:
|
|||
|
||||
void render(int screenWidth, int screenHeight);
|
||||
|
||||
void setMixerLoopbackFlag(bool mixerLoopbackFlag) { _mixerLoopbackFlag = mixerLoopbackFlag; }
|
||||
|
||||
float getLastInputLoudness() const { return _lastInputLoudness; };
|
||||
|
||||
void setLastAcceleration(glm::vec3 lastAcceleration) { _lastAcceleration = lastAcceleration; };
|
||||
|
@ -52,7 +50,6 @@ private:
|
|||
short _jitterBufferSamples;
|
||||
int _wasStarved;
|
||||
float _lastInputLoudness;
|
||||
bool _mixerLoopbackFlag;
|
||||
glm::vec3 _lastVelocity;
|
||||
glm::vec3 _lastAcceleration;
|
||||
int _totalPacketsReceived;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,6 @@
|
|||
// Avatar.h
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 9/11/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
|
@ -12,15 +11,49 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <AvatarData.h>
|
||||
#include <Orientation.h>
|
||||
#include "world.h"
|
||||
#include "AvatarTouch.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "SerialInterface.h"
|
||||
#include "Balls.h"
|
||||
#include "Head.h"
|
||||
#include "Skeleton.h"
|
||||
#include "Transmitter.h"
|
||||
|
||||
|
||||
enum AvatarBodyBallID
|
||||
{
|
||||
BODY_BALL_NULL = -1,
|
||||
BODY_BALL_PELVIS,
|
||||
BODY_BALL_TORSO,
|
||||
BODY_BALL_CHEST,
|
||||
BODY_BALL_NECK_BASE,
|
||||
BODY_BALL_HEAD_BASE,
|
||||
BODY_BALL_HEAD_TOP,
|
||||
BODY_BALL_LEFT_COLLAR,
|
||||
BODY_BALL_LEFT_SHOULDER,
|
||||
BODY_BALL_LEFT_ELBOW,
|
||||
BODY_BALL_LEFT_WRIST,
|
||||
BODY_BALL_LEFT_FINGERTIPS,
|
||||
BODY_BALL_RIGHT_COLLAR,
|
||||
BODY_BALL_RIGHT_SHOULDER,
|
||||
BODY_BALL_RIGHT_ELBOW,
|
||||
BODY_BALL_RIGHT_WRIST,
|
||||
BODY_BALL_RIGHT_FINGERTIPS,
|
||||
BODY_BALL_LEFT_HIP,
|
||||
BODY_BALL_LEFT_KNEE,
|
||||
BODY_BALL_LEFT_HEEL,
|
||||
BODY_BALL_LEFT_TOES,
|
||||
BODY_BALL_RIGHT_HIP,
|
||||
BODY_BALL_RIGHT_KNEE,
|
||||
BODY_BALL_RIGHT_HEEL,
|
||||
BODY_BALL_RIGHT_TOES,
|
||||
|
||||
//TEST!
|
||||
//BODY_BALL_LEFT_MID_THIGH,
|
||||
NUM_AVATAR_BODY_BALLS
|
||||
};
|
||||
|
||||
enum DriveKeys
|
||||
{
|
||||
FWD = 0,
|
||||
|
@ -31,98 +64,67 @@ enum DriveKeys
|
|||
DOWN,
|
||||
ROT_LEFT,
|
||||
ROT_RIGHT,
|
||||
MAX_DRIVE_KEYS
|
||||
MAX_DRIVE_KEYS
|
||||
};
|
||||
|
||||
enum AvatarMode
|
||||
{
|
||||
AVATAR_MODE_STANDING = 0,
|
||||
AVATAR_MODE_WALKING,
|
||||
AVATAR_MODE_INTERACTING,
|
||||
NUM_AVATAR_MODES
|
||||
AVATAR_MODE_STANDING = 0,
|
||||
AVATAR_MODE_WALKING,
|
||||
AVATAR_MODE_INTERACTING,
|
||||
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);
|
||||
void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight);
|
||||
void addBodyYaw(float y) {_bodyYaw += y;};
|
||||
void render(bool lookingInMirror);
|
||||
|
||||
//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);
|
||||
void setOrientation (const glm::quat& orientation);
|
||||
|
||||
//getters
|
||||
float getHeadYawRate () const { return _head.yawRate;}
|
||||
float getBodyYaw () const { return _bodyYaw;}
|
||||
bool getIsNearInteractingOther () const { return _avatarTouch.getAbleToReachOtherAvatar();}
|
||||
const glm::vec3& getHeadJointPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;}
|
||||
const glm::vec3& getBallPosition (AvatarJointID j) const { return _bodyBall[j].position;}
|
||||
glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; }
|
||||
glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; }
|
||||
glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; }
|
||||
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; }
|
||||
glm::quat getOrientation () const;
|
||||
glm::quat getWorldAlignedOrientation() const;
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -131,26 +133,23 @@ private:
|
|||
Avatar(const Avatar&);
|
||||
Avatar& operator= (const Avatar&);
|
||||
|
||||
struct AvatarJoint
|
||||
struct AvatarBall
|
||||
{
|
||||
AvatarJointID parent; // which joint is this joint connected to?
|
||||
glm::vec3 position; // the position at the "end" of the joint - in global space
|
||||
glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose"
|
||||
glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position)
|
||||
glm::vec3 springyVelocity; // used for special effects ( the velocity of the springy position)
|
||||
float springBodyTightness; // how tightly the springy position tries to stay on the position
|
||||
glm::quat rotation; // this will eventually replace yaw, pitch and roll (and maybe orientation)
|
||||
float yaw; // the yaw Euler angle of the joint rotation off the parent
|
||||
float pitch; // the pitch Euler angle of the joint rotation off the parent
|
||||
float roll; // the roll Euler angle of the joint rotation off the parent
|
||||
Orientation orientation; // three orthogonal normals determined by yaw, pitch, roll
|
||||
float length; // the length of vector connecting the joint and its parent
|
||||
float radius; // used for detecting collisions for certain physical effects
|
||||
bool isCollidable; // when false, the joint position will not register a collision
|
||||
float touchForce; // if being touched, what's the degree of influence? (0 to 1)
|
||||
AvatarJointID parentJoint; // the skeletal joint that serves as a reference for determining the position
|
||||
glm::vec3 parentOffset; // a 3D vector in the frame of reference of the parent skeletal joint
|
||||
AvatarBodyBallID parentBall; // the ball to which this ball is constrained for spring forces
|
||||
glm::vec3 position; // the actual dynamic position of the ball at any given time
|
||||
glm::vec3 velocity; // the velocity of the ball
|
||||
float springLength; // the ideal length of the spring between this ball and its parentBall
|
||||
float jointTightness; // how tightly the ball position attempts to stay at its ideal position (determined by parentOffset)
|
||||
float radius; // the radius of the ball
|
||||
bool isCollidable; // whether or not the ball responds to collisions
|
||||
float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball
|
||||
};
|
||||
|
||||
Head _head;
|
||||
Skeleton _skeleton;
|
||||
bool _ballSpringsInitialized;
|
||||
float _TEST_bigSphereRadius;
|
||||
glm::vec3 _TEST_bigSpherePosition;
|
||||
bool _mousePressed;
|
||||
|
@ -158,16 +157,14 @@ private:
|
|||
float _bodyYawDelta;
|
||||
float _bodyRollDelta;
|
||||
glm::vec3 _movedHandOffset;
|
||||
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
|
||||
AvatarJoint _joint[ NUM_AVATAR_JOINTS ];
|
||||
AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ];
|
||||
AvatarMode _mode;
|
||||
glm::vec3 _cameraPosition;
|
||||
glm::vec3 _handHoldingPosition;
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _thrust;
|
||||
glm::vec3 _thrust;
|
||||
float _speed;
|
||||
float _maxArmLength;
|
||||
Orientation _orientation;
|
||||
float _maxArmLength;
|
||||
glm::quat _righting;
|
||||
int _driveKeys[MAX_DRIVE_KEYS];
|
||||
float _pelvisStandingHeight;
|
||||
|
@ -177,6 +174,7 @@ private:
|
|||
AvatarTouch _avatarTouch;
|
||||
float _distanceToNearestAvatar; // How close is the nearest avatar?
|
||||
glm::vec3 _gravity;
|
||||
glm::vec3 _worldUpDirection;
|
||||
glm::vec3 _mouseRayOrigin;
|
||||
glm::vec3 _mouseRayDirection;
|
||||
Avatar* _interactingOther;
|
||||
|
@ -184,14 +182,17 @@ private:
|
|||
bool _isMouseTurningRight;
|
||||
|
||||
// private methods...
|
||||
void initializeSkeleton();
|
||||
void updateSkeleton();
|
||||
void initializeBodySprings();
|
||||
void updateBodySprings( float deltaTime );
|
||||
glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat)
|
||||
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
|
||||
void renderBody(bool lookingInMirror);
|
||||
void initializeBodyBalls();
|
||||
void resetBodyBalls();
|
||||
void updateBodyBalls( float deltaTime );
|
||||
void calculateBoneLengths();
|
||||
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();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
const float THREAD_RADIUS = 0.007;
|
||||
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.2;
|
||||
const float AVATAR_FACING_THRESHOLD = -0.5f; // (-1 to 1) (larger value indicates narrower angle of influence
|
||||
|
||||
AvatarTouch::AvatarTouch() {
|
||||
|
||||
|
@ -27,61 +28,55 @@ AvatarTouch::AvatarTouch() {
|
|||
_weAreHoldingHands = false;
|
||||
_canReachToOtherAvatar = false;
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
_hasInteractingOther = false;
|
||||
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
for (int p=0; p<NUM_PARTICLE_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);
|
||||
_canReachToOtherAvatar = false; // default
|
||||
|
||||
if (distanceBetweenBodies < _reachableRadius) {
|
||||
_vectorBetweenHands = _yourHandPosition - _myHandPosition;
|
||||
if (_hasInteractingOther) {
|
||||
|
||||
glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition;
|
||||
float distanceBetweenBodies = glm::length(vectorBetweenBodies);
|
||||
|
||||
float distanceBetweenHands = glm::length(_vectorBetweenHands);
|
||||
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
|
||||
_handsCloseEnoughToGrasp = true;
|
||||
} else {
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
//KEEP THIS - it is another variation that we are considering getting rid of
|
||||
//the following code take into account of the two avatars are facing each other
|
||||
/*
|
||||
glm::vec3 directionBetweenBodies = vectorBetweenBodies / distanceBetweenBodies;
|
||||
|
||||
bool facingEachOther = false;
|
||||
|
||||
glm::vec3 myFront = _myOrientation * AVATAR_FRONT;
|
||||
glm::vec3 yourFront = _yourOrientation * AVATAR_FRONT;
|
||||
|
||||
if (( glm::dot(myFront, yourFront ) < -AVATAR_FACING_THRESHOLD) // we're facing each other
|
||||
&& ( glm::dot(myFront, directionBetweenBodies ) > AVATAR_FACING_THRESHOLD)) { // I'm facing you
|
||||
facingEachOther = true;
|
||||
}
|
||||
*/
|
||||
|
||||
_canReachToOtherAvatar = true;
|
||||
} else {
|
||||
_canReachToOtherAvatar = false;
|
||||
}
|
||||
if (distanceBetweenBodies < _reachableRadius)
|
||||
{
|
||||
_canReachToOtherAvatar = true;
|
||||
|
||||
_vectorBetweenHands = _yourHandPosition - _myHandPosition;
|
||||
|
||||
float distanceBetweenHands = glm::length(_vectorBetweenHands);
|
||||
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
|
||||
_handsCloseEnoughToGrasp = true;
|
||||
} else {
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AvatarTouch::render(glm::vec3 cameraPosition) {
|
||||
|
||||
if (_canReachToOtherAvatar) {
|
||||
|
@ -92,7 +87,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();
|
||||
|
||||
|
@ -147,7 +142,6 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
void AvatarTouch::renderBeamBetweenHands() {
|
||||
|
||||
glm::vec3 v1(_myHandPosition);
|
||||
|
@ -161,9 +155,9 @@ void AvatarTouch::renderBeamBetweenHands() {
|
|||
glEnd();
|
||||
|
||||
glColor3f(0.5f, 0.3f, 0.0f);
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
for (int p=0; p<NUM_PARTICLE_POINTS; p++) {
|
||||
|
||||
_point[p] = _myHandPosition + _vectorBetweenHands * ((float)p / (float)NUM_POINTS);
|
||||
_point[p] = _myHandPosition + _vectorBetweenHands * ((float)p / (float)NUM_PARTICLE_POINTS);
|
||||
_point[p].x += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
|
||||
_point[p].y += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
|
||||
_point[p].z += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#define __interface__AvatarTouch__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <AvatarData.h>
|
||||
|
||||
enum AvatarHandState
|
||||
{
|
||||
|
@ -26,18 +29,18 @@ 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 setHasInteractingOther(bool hasInteractingOther) { _hasInteractingOther = hasInteractingOther;}
|
||||
void setMyHandPosition (glm::vec3 position ) { _myHandPosition = position;}
|
||||
void setYourHandPosition (glm::vec3 position ) { _yourHandPosition = position;}
|
||||
void setMyOrientation (glm::quat orientation ) { _myOrientation = orientation;}
|
||||
void setYourOrientation (glm::quat 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;}
|
||||
|
@ -45,20 +48,23 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
static const int NUM_POINTS = 100;
|
||||
static const int NUM_PARTICLE_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 _hasInteractingOther;
|
||||
bool _weAreHoldingHands;
|
||||
glm::vec3 _point [NUM_PARTICLE_POINTS];
|
||||
glm::vec3 _myBodyPosition;
|
||||
glm::vec3 _yourBodyPosition;
|
||||
glm::vec3 _myHandPosition;
|
||||
glm::vec3 _yourHandPosition;
|
||||
glm::quat _myOrientation;
|
||||
glm::quat _yourOrientation;
|
||||
glm::vec3 _vectorBetweenHands;
|
||||
int _myHandState;
|
||||
int _yourHandState;
|
||||
bool _canReachToOtherAvatar;
|
||||
bool _handsCloseEnoughToGrasp;
|
||||
float _reachableRadius;
|
||||
|
||||
void renderBeamBetweenHands();
|
||||
};
|
||||
|
|
|
@ -4,56 +4,53 @@
|
|||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <SharedUtil.h>
|
||||
#include <VoxelConstants.h>
|
||||
#include <OculusManager.h>
|
||||
// #include "Log.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "Camera.h"
|
||||
#include "Util.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);
|
||||
_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;
|
||||
}
|
||||
_modeShift = 1.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
|
||||
_upShift = 0.0f;
|
||||
_distance = 0.0f;
|
||||
_previousUpShift = 0.0f;
|
||||
_previousDistance = 0.0f;
|
||||
_previousTightness = 0.0f;
|
||||
_newUpShift = 0.0f;
|
||||
_newDistance = 0.0f;
|
||||
_newTightness = 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);
|
||||
}
|
||||
|
||||
void Camera::update(float deltaTime) {
|
||||
|
@ -62,60 +59,44 @@ void Camera::update(float deltaTime) {
|
|||
// use iterative forces to push the camera towards the target position and angle
|
||||
updateFollowMode(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 );
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// update Euler angles (before position!)
|
||||
// update rotation (before position!)
|
||||
if (_needsToInitialize || OculusManager::isConnected()) {
|
||||
_yaw = _idealYaw;
|
||||
_pitch = _idealPitch;
|
||||
_roll = _idealRoll;
|
||||
_rotation = _targetRotation;
|
||||
} else {
|
||||
// pull Euler angles towards ideal Euler angles
|
||||
_yaw += (_idealYaw - _yaw ) * t;
|
||||
_pitch += (_idealPitch - _pitch) * t;
|
||||
_roll += (_idealRoll - _roll ) * t;
|
||||
// pull rotation towards ideal
|
||||
_rotation = safeMix(_rotation, _targetRotation, t);
|
||||
}
|
||||
|
||||
_orientation.yaw (_yaw );
|
||||
_orientation.pitch(_pitch);
|
||||
_orientation.roll (_roll );
|
||||
|
||||
float radian = (_yaw / 180.0) * PIE;
|
||||
|
||||
// update _position
|
||||
double x = -_distance * sin(radian);
|
||||
double z = -_distance * cos(radian);
|
||||
double y = _upShift;
|
||||
|
||||
_idealPosition = _targetPosition + glm::vec3(x, y, z);
|
||||
_idealPosition = _targetPosition + _rotation * glm::vec3(0.0f, _upShift, _distance);
|
||||
|
||||
if (_needsToInitialize) {
|
||||
_position = _idealPosition;
|
||||
|
@ -124,36 +105,47 @@ 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;
|
||||
_idealRoll = roll;
|
||||
|
||||
void Camera::setTargetRotation( const glm::quat& targetRotation ) {
|
||||
_targetRotation = targetRotation;
|
||||
}
|
||||
|
||||
void Camera::setFieldOfView(float f) {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#ifndef __interface__camera__
|
||||
#define __interface__camera__
|
||||
|
||||
#include "Orientation.h"
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
|
@ -21,69 +20,45 @@ 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 );
|
||||
|
||||
void setYaw ( float y ) { _yaw = y; }
|
||||
void setPitch ( float p ) { _pitch = p; }
|
||||
void setRoll ( float r ) { _roll = r; }
|
||||
void setUpShift ( float u ) { _upShift = u; }
|
||||
void setDistance ( float d ) { _distance = d; }
|
||||
void setTargetPosition( glm::vec3 t ) { _targetPosition = t; }
|
||||
void setTargetYaw ( float y ) { _idealYaw = y; }
|
||||
void setPosition ( glm::vec3 p ) { _position = p; }
|
||||
void setTightness ( float t ) { _tightness = t; }
|
||||
void setTargetRotation( float yaw, float pitch, float roll );
|
||||
void setUpShift ( float u ) { _upShift = u; }
|
||||
void setDistance ( float d ) { _distance = d; }
|
||||
void setTargetPosition( const glm::vec3& t ) { _targetPosition = t; }
|
||||
void setPosition ( const glm::vec3& p ) { _position = p; }
|
||||
void setTightness ( float t ) { _tightness = t; }
|
||||
void setTargetRotation( const glm::quat& rotation );
|
||||
|
||||
void setMode ( CameraMode m );
|
||||
void setMode ( CameraMode m, CameraFollowingAttributes attributes );
|
||||
void setFieldOfView ( float f );
|
||||
void setAspectRatio ( float a );
|
||||
void setNearClip ( float n );
|
||||
void setFarClip ( float f );
|
||||
void setEyeOffsetPosition ( const glm::vec3& p);
|
||||
void setEyeOffsetOrientation ( const glm::quat& o);
|
||||
|
||||
float getYaw () { return _yaw; }
|
||||
float getPitch () { return _pitch; }
|
||||
float getRoll () { return _roll; }
|
||||
glm::vec3 getPosition () { return _position; }
|
||||
Orientation getOrientation() { return _orientation; }
|
||||
CameraMode getMode () { return _mode; }
|
||||
float getFieldOfView() { return _fieldOfView; }
|
||||
float getAspectRatio() { return _aspectRatio; }
|
||||
float getNearClip () { return _nearClip; }
|
||||
float getFarClip () { return _farClip; }
|
||||
glm::vec3 getEyeOffsetPosition () { return _eyeOffsetPosition; }
|
||||
glm::quat getEyeOffsetOrientation () { return _eyeOffsetOrientation; }
|
||||
bool getFrustumNeedsReshape(); // call to find out if the view frustum needs to be reshaped
|
||||
void setFrustumWasReshaped(); // call this after reshaping the view frustum.
|
||||
void setMode ( CameraMode m );
|
||||
void setModeShiftRate ( float r );
|
||||
void setFieldOfView ( float f );
|
||||
void setAspectRatio ( float a );
|
||||
void setNearClip ( float n );
|
||||
void setFarClip ( float f );
|
||||
void setEyeOffsetPosition ( const glm::vec3& p );
|
||||
void setEyeOffsetOrientation( const glm::quat& o );
|
||||
|
||||
const glm::vec3& getTargetPosition () { return _targetPosition; }
|
||||
const glm::vec3& getPosition () { return _position; }
|
||||
const glm::quat& getTargetRotation () { return _targetRotation; }
|
||||
const glm::quat& getRotation () { return _rotation; }
|
||||
CameraMode getMode () { return _mode; }
|
||||
float getFieldOfView () { return _fieldOfView; }
|
||||
float getAspectRatio () { return _aspectRatio; }
|
||||
float getNearClip () { return _nearClip; }
|
||||
float getFarClip () { return _farClip; }
|
||||
const glm::vec3& getEyeOffsetPosition () { return _eyeOffsetPosition; }
|
||||
const glm::quat& getEyeOffsetOrientation () { return _eyeOffsetOrientation; }
|
||||
|
||||
bool getFrustumNeedsReshape(); // call to find out if the view frustum needs to be reshaped
|
||||
void setFrustumWasReshaped(); // call this after reshaping the view frustum.
|
||||
|
||||
private:
|
||||
|
||||
|
@ -99,22 +74,21 @@ private:
|
|||
float _farClip;
|
||||
glm::vec3 _eyeOffsetPosition;
|
||||
glm::quat _eyeOffsetOrientation;
|
||||
float _yaw;
|
||||
float _pitch;
|
||||
float _roll;
|
||||
glm::quat _rotation;
|
||||
glm::quat _targetRotation;
|
||||
float _upShift;
|
||||
float _idealYaw;
|
||||
float _idealPitch;
|
||||
float _idealRoll;
|
||||
float _distance;
|
||||
float _tightness;
|
||||
Orientation _orientation;
|
||||
float _previousUpShift;
|
||||
float _previousDistance;
|
||||
float _previousTightness;
|
||||
float _newUpShift;
|
||||
float _newDistance;
|
||||
float _newTightness;
|
||||
float _modeShift;
|
||||
float _linearModeShift;
|
||||
float _modeShiftRate;
|
||||
|
||||
CameraFollowingAttributes _attributes[NUM_CAMERA_MODES];
|
||||
CameraFollowingAttributes _previousAttributes[NUM_CAMERA_MODES];
|
||||
|
||||
void generateOrientation();
|
||||
void updateFollowMode( float deltaTime );
|
||||
};
|
||||
|
||||
|
|
|
@ -58,11 +58,17 @@ void Environment::renderAtmospheres(Camera& camera) {
|
|||
}
|
||||
|
||||
glm::vec3 Environment::getGravity (const glm::vec3& position) {
|
||||
// the "original gravity"
|
||||
glm::vec3 gravity;
|
||||
if (position.x > 0.0f && position.x < 10.0f && position.y > 0.0f &&
|
||||
position.y < 3.0f && position.z > 0.0f && position.z < 10.0f) {
|
||||
gravity = glm::vec3(0.0f, -1.0f, 0.0f);
|
||||
//
|
||||
// 'Default' gravity pulls you downward in Y when you are near the X/Z plane
|
||||
const glm::vec3 DEFAULT_GRAVITY(0.f, -1.f, 0.f);
|
||||
glm::vec3 gravity(DEFAULT_GRAVITY);
|
||||
float DEFAULT_SURFACE_RADIUS = 30.f;
|
||||
float gravityStrength;
|
||||
|
||||
// Weaken gravity with height
|
||||
if (position.y > 0.f) {
|
||||
gravityStrength = 1.f / powf((DEFAULT_SURFACE_RADIUS + position.y) / DEFAULT_SURFACE_RADIUS, 2.f);
|
||||
gravity *= gravityStrength;
|
||||
}
|
||||
|
||||
// get the lock for the duration of the call
|
||||
|
@ -71,11 +77,18 @@ glm::vec3 Environment::getGravity (const glm::vec3& position) {
|
|||
foreach (const ServerData& serverData, _data) {
|
||||
foreach (const EnvironmentData& environmentData, serverData) {
|
||||
glm::vec3 vector = environmentData.getAtmosphereCenter() - position;
|
||||
if (glm::length(vector) < environmentData.getAtmosphereOuterRadius()) {
|
||||
float surfaceRadius = environmentData.getAtmosphereInnerRadius();
|
||||
if (glm::length(vector) <= surfaceRadius) {
|
||||
// At or inside a planet, gravity is as set for the planet
|
||||
gravity += glm::normalize(vector) * environmentData.getGravity();
|
||||
} else {
|
||||
// Outside a planet, the gravity falls off with distance
|
||||
gravityStrength = 1.f / powf(glm::length(vector) / surfaceRadius, 2.f);
|
||||
gravity += glm::normalize(vector) * environmentData.getGravity() * gravityStrength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gravity;
|
||||
}
|
||||
|
||||
|
@ -101,13 +114,7 @@ const EnvironmentData Environment::getClosestData(const glm::vec3& position) {
|
|||
bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end,
|
||||
float radius, glm::vec3& penetration) {
|
||||
// collide with the "floor"
|
||||
bool found = false;
|
||||
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
float floorDist = qMin(start.y, end.y) - radius;
|
||||
if (floorDist < 0.0f) {
|
||||
penetration.y = -floorDist;
|
||||
found = true;
|
||||
}
|
||||
bool found = findCapsulePlanePenetration(start, end, radius, glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), penetration);
|
||||
|
||||
// get the lock for the duration of the call
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
@ -117,11 +124,10 @@ bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3
|
|||
if (environmentData.getGravity() == 0.0f) {
|
||||
continue; // don't bother colliding with gravity-less environments
|
||||
}
|
||||
glm::vec3 vector = computeVectorFromPointToSegment(environmentData.getAtmosphereCenter(), start, end);
|
||||
float vectorLength = glm::length(vector);
|
||||
float distance = vectorLength - environmentData.getAtmosphereInnerRadius() - radius;
|
||||
if (distance < 0.0f) {
|
||||
penetration += vector * (-distance / vectorLength);
|
||||
glm::vec3 environmentPenetration;
|
||||
if (findCapsuleSpherePenetration(start, end, radius, environmentData.getAtmosphereCenter(),
|
||||
environmentData.getAtmosphereInnerRadius(), environmentPenetration)) {
|
||||
penetration = addPenetrations(penetration, environmentPenetration);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include "Avatar.h"
|
||||
#include "Head.h"
|
||||
#include "Util.h"
|
||||
#include <vector>
|
||||
|
@ -13,17 +15,16 @@
|
|||
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_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;
|
||||
|
@ -41,8 +42,8 @@ vector<unsigned char> irisTexture;
|
|||
Head::Head(Avatar* owningAvatar) :
|
||||
HeadData((AvatarData*)owningAvatar),
|
||||
yawRate(0.0f),
|
||||
_renderAlpha(0.0),
|
||||
_returnHeadToCenter(false),
|
||||
_audioLoudness(0.0f),
|
||||
_skinColor(0.0f, 0.0f, 0.0f),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_rotation(0.0f, 0.0f, 0.0f),
|
||||
|
@ -62,37 +63,43 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_audioAttack(0.0f),
|
||||
_returnSpringScale(1.0f),
|
||||
_bodyRotation(0.0f, 0.0f, 0.0f),
|
||||
_lookingInMirror(false),
|
||||
_renderLookatVectors(false),
|
||||
_mohawkTriangleFan(NULL),
|
||||
_mohawkColors(NULL) {
|
||||
|
||||
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);
|
||||
}
|
||||
_mohawkColors(NULL)
|
||||
{
|
||||
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() {
|
||||
glm::vec3 up = getUpDirection();
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
|
||||
_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;
|
||||
_hairTuft[t].length = HAIR_LENGTH;
|
||||
_hairTuft[t].thickness = HAIR_THICKNESS;
|
||||
_hairTuft[t].basePosition = _position + up * _scale * 0.9f;
|
||||
_hairTuft[t].midPosition = _hairTuft[t].basePosition + up * _hairTuft[t].length * ONE_HALF;
|
||||
_hairTuft[t].endPosition = _hairTuft[t].midPosition + up * _hairTuft[t].length * ONE_HALF;
|
||||
_hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Head::simulate(float deltaTime, bool isMine) {
|
||||
|
||||
const float HEAD_MOTION_DECAY = 0.00;
|
||||
|
@ -141,7 +148,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() {
|
||||
|
@ -150,7 +159,7 @@ void Head::determineIfLookingAtSomething() {
|
|||
_lookingAtSomething = false;
|
||||
} else {
|
||||
glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - caclulateAverageEyePosition());
|
||||
float dot = glm::dot(targetLookatAxis, _orientation.getFront());
|
||||
float dot = glm::dot(targetLookatAxis, getFrontDirection());
|
||||
if (dot < MINIMUM_EYE_ROTATION_DOT) { // too far off from center for the eyes to rotate
|
||||
_lookingAtSomething = false;
|
||||
} else {
|
||||
|
@ -159,67 +168,60 @@ void Head::determineIfLookingAtSomething() {
|
|||
}
|
||||
}
|
||||
|
||||
void Head::calculateGeometry(bool lookingInMirror) {
|
||||
//generate orientation directions based on Euler angles...
|
||||
|
||||
float pitch = _pitch;
|
||||
float yaw = _yaw;
|
||||
float roll = _roll;
|
||||
|
||||
if (lookingInMirror) {
|
||||
yaw = -_yaw;
|
||||
roll = -_roll;
|
||||
}
|
||||
|
||||
_orientation.setToIdentity();
|
||||
_orientation.roll (_bodyRotation.z + roll );
|
||||
_orientation.pitch(_bodyRotation.x + pitch);
|
||||
_orientation.yaw (_bodyRotation.y + yaw );
|
||||
void Head::calculateGeometry() {
|
||||
//generate orientation directions
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::vec3 right = orientation * AVATAR_RIGHT;
|
||||
glm::vec3 up = orientation * AVATAR_UP;
|
||||
glm::vec3 front = orientation * AVATAR_FRONT;
|
||||
|
||||
//calculate the eye positions
|
||||
_leftEyePosition = _position
|
||||
- _orientation.getRight() * _scale * EYE_RIGHT_OFFSET
|
||||
+ _orientation.getUp () * _scale * EYE_UP_OFFSET
|
||||
+ _orientation.getFront() * _scale * EYE_FRONT_OFFSET;
|
||||
- right * _scale * EYE_RIGHT_OFFSET
|
||||
+ up * _scale * EYE_UP_OFFSET
|
||||
+ front * _scale * EYE_FRONT_OFFSET;
|
||||
_rightEyePosition = _position
|
||||
+ _orientation.getRight() * _scale * EYE_RIGHT_OFFSET
|
||||
+ _orientation.getUp () * _scale * EYE_UP_OFFSET
|
||||
+ _orientation.getFront() * _scale * EYE_FRONT_OFFSET;
|
||||
+ right * _scale * EYE_RIGHT_OFFSET
|
||||
+ up * _scale * EYE_UP_OFFSET
|
||||
+ front * _scale * EYE_FRONT_OFFSET;
|
||||
|
||||
//calculate the eyebrow positions
|
||||
_leftEyeBrowPosition = _leftEyePosition;
|
||||
_rightEyeBrowPosition = _rightEyePosition;
|
||||
|
||||
//calculate the ear positions
|
||||
_leftEarPosition = _position - _orientation.getRight() * _scale * EAR_RIGHT_OFFSET;
|
||||
_rightEarPosition = _position + _orientation.getRight() * _scale * EAR_RIGHT_OFFSET;
|
||||
_leftEarPosition = _position - right * _scale * EAR_RIGHT_OFFSET;
|
||||
_rightEarPosition = _position + right * _scale * EAR_RIGHT_OFFSET;
|
||||
|
||||
//calculate the mouth position
|
||||
_mouthPosition = _position + _orientation.getUp () * _scale * MOUTH_UP_OFFSET
|
||||
+ _orientation.getFront() * _scale * MOUTH_FRONT_OFFSET;
|
||||
_mouthPosition = _position + up * _scale * MOUTH_UP_OFFSET
|
||||
+ front * _scale;
|
||||
}
|
||||
|
||||
|
||||
void Head::render(bool lookingInMirror, glm::vec3 cameraPosition) {
|
||||
void Head::render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha) {
|
||||
|
||||
calculateGeometry(lookingInMirror);
|
||||
_renderAlpha = alpha;
|
||||
_lookingInMirror = lookingInMirror;
|
||||
|
||||
calculateGeometry();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_RESCALE_NORMAL);
|
||||
|
||||
renderMohawk(lookingInMirror);
|
||||
renderMohawk(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()) {
|
||||
|
@ -251,14 +253,46 @@ void Head::createMohawk() {
|
|||
}
|
||||
}
|
||||
|
||||
void Head::renderMohawk(bool lookingInMirror) {
|
||||
void Head::renderMohawk(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);
|
||||
glRotatef((lookingInMirror ? (_bodyRotation.y - _yaw) : (_bodyRotation.y + _yaw)), 0, 1, 0);
|
||||
glRotatef(lookingInMirror ? _roll: -_roll, 0, 0, 1);
|
||||
glRotatef((_lookingInMirror ? (_bodyRotation.y - _yaw) : (_bodyRotation.y + _yaw)), 0, 1, 0);
|
||||
glRotatef(_lookingInMirror ? _roll: -_roll, 0, 0, 1);
|
||||
glRotatef(-_pitch - _bodyRotation.x, 1, 0, 0);
|
||||
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
|
@ -269,15 +303,25 @@ void Head::renderMohawk(bool lookingInMirror) {
|
|||
}
|
||||
glEnd();
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::quat Head::getOrientation() const {
|
||||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(_lookingInMirror ?
|
||||
glm::vec3(_pitch, -_yaw, -_roll) : glm::vec3(_pitch, _yaw, _roll)));
|
||||
}
|
||||
|
||||
glm::quat Head::getWorldAlignedOrientation () const {
|
||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
|
||||
return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(_lookingInMirror ?
|
||||
glm::vec3(_pitch, -_yaw, -_roll) : glm::vec3(_pitch, _yaw, _roll)));
|
||||
}
|
||||
|
||||
void Head::renderHeadSphere() {
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z); //translate to head position
|
||||
glScalef(_scale, _scale, _scale); //scale to head size
|
||||
glColor3f(_skinColor.x, _skinColor.y, _skinColor.z);
|
||||
glColor4f(_skinColor.x, _skinColor.y, _skinColor.z, _renderAlpha);
|
||||
glutSolidSphere(1, 30, 30);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -285,13 +329,13 @@ void Head::renderHeadSphere() {
|
|||
void Head::renderEars() {
|
||||
|
||||
glPushMatrix();
|
||||
glColor3f(_skinColor.x, _skinColor.y, _skinColor.z);
|
||||
glColor4f(_skinColor.x, _skinColor.y, _skinColor.z, _renderAlpha);
|
||||
glTranslatef(_leftEarPosition.x, _leftEarPosition.y, _leftEarPosition.z);
|
||||
glutSolidSphere(0.02, 30, 30);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glColor3f(_skinColor.x, _skinColor.y, _skinColor.z);
|
||||
glColor4f(_skinColor.x, _skinColor.y, _skinColor.z, _renderAlpha);
|
||||
glTranslatef(_rightEarPosition.x, _rightEarPosition.y, _rightEarPosition.z);
|
||||
glutSolidSphere(0.02, 30, 30);
|
||||
glPopMatrix();
|
||||
|
@ -301,10 +345,16 @@ void Head::renderMouth() {
|
|||
|
||||
float s = sqrt(_averageLoudness);
|
||||
|
||||
glm::vec3 r = _orientation.getRight() * _scale * (0.30f + s * 0.0014f );
|
||||
glm::vec3 u = _orientation.getUp () * _scale * (0.05f + s * 0.0040f );
|
||||
glm::vec3 f = _orientation.getFront() * _scale * 0.09f;
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::vec3 right = orientation * AVATAR_RIGHT;
|
||||
glm::vec3 up = orientation * AVATAR_UP;
|
||||
glm::vec3 front = orientation * AVATAR_FRONT;
|
||||
|
||||
glm::vec3 r = right * _scale * (0.30f + s * 0.0014f );
|
||||
glm::vec3 u = up * _scale * (0.05f + s * 0.0040f );
|
||||
glm::vec3 f = front * _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,14 +363,17 @@ void Head::renderMouth() {
|
|||
glm::vec3 rightBottom = _mouthPosition + r * 0.4f - u * 1.0f + f * 0.7f;
|
||||
|
||||
// constrain all mouth vertices to a sphere slightly larger than the head...
|
||||
float constrainedRadius = _scale + 0.001f;
|
||||
const float MOUTH_OFFSET_OFF_FACE = 0.003f;
|
||||
|
||||
float constrainedRadius = _scale + MOUTH_OFFSET_OFF_FACE;
|
||||
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;
|
||||
rightTop = _position + glm::normalize(rightTop - _position) * constrainedRadius;
|
||||
leftBottom = _position + glm::normalize(leftBottom - _position) * constrainedRadius;
|
||||
rightBottom = _position + glm::normalize(rightBottom - _position) * constrainedRadius;
|
||||
|
||||
|
||||
glColor3f(0.2f, 0.0f, 0.0f);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
@ -328,10 +381,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);
|
||||
|
@ -353,11 +412,16 @@ void Head::renderEyeBrows() {
|
|||
glm::vec3 rightTop = _leftEyePosition;
|
||||
glm::vec3 leftBottom = _leftEyePosition;
|
||||
glm::vec3 rightBottom = _leftEyePosition;
|
||||
|
||||
glm::vec3 r = _orientation.getRight() * length;
|
||||
glm::vec3 u = _orientation.getUp() * height;
|
||||
glm::vec3 t = _orientation.getUp() * (height + width);
|
||||
glm::vec3 f = _orientation.getFront() * _scale * -0.1f;
|
||||
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::vec3 right = orientation * AVATAR_RIGHT;
|
||||
glm::vec3 up = orientation * AVATAR_UP;
|
||||
glm::vec3 front = orientation * AVATAR_FRONT;
|
||||
|
||||
glm::vec3 r = right * length;
|
||||
glm::vec3 u = up * height;
|
||||
glm::vec3 t = up * (height + width);
|
||||
glm::vec3 f = front * _scale * -0.1f;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
|
@ -425,6 +489,8 @@ void Head::renderEyeBalls() {
|
|||
gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30);
|
||||
glPopMatrix();
|
||||
|
||||
glm::vec3 front = getFrontDirection();
|
||||
|
||||
// render left iris
|
||||
glPushMatrix(); {
|
||||
glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position
|
||||
|
@ -435,20 +501,20 @@ void Head::renderEyeBalls() {
|
|||
|
||||
//rotate the eyeball to aim towards the lookat position
|
||||
glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _leftEyePosition); // the lookat direction
|
||||
glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP);
|
||||
float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP);
|
||||
glm::vec3 rotationAxis = glm::cross(targetLookatAxis, AVATAR_UP);
|
||||
float angle = 180.0f - angleBetween(targetLookatAxis, AVATAR_UP);
|
||||
glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
||||
glRotatef(180.0, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations
|
||||
} else {
|
||||
|
||||
//rotate the eyeball to aim straight ahead
|
||||
glm::vec3 rotationAxisToHeadFront = glm::cross(_orientation.getFront(), IDENTITY_UP);
|
||||
float angleToHeadFront = 180.0f - angleBetween(_orientation.getFront(), IDENTITY_UP);
|
||||
glm::vec3 rotationAxisToHeadFront = glm::cross(front, AVATAR_UP);
|
||||
float angleToHeadFront = 180.0f - angleBetween(front, AVATAR_UP);
|
||||
glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z);
|
||||
|
||||
//set the amount of roll (for correction after previous rotations)
|
||||
float rollRotation = angleBetween(_orientation.getFront(), IDENTITY_FRONT);
|
||||
float dot = glm::dot(_orientation.getFront(), -IDENTITY_RIGHT);
|
||||
float rollRotation = angleBetween(front, AVATAR_FRONT);
|
||||
float dot = glm::dot(front, -AVATAR_RIGHT);
|
||||
if ( dot < 0.0f ) { rollRotation = -rollRotation; }
|
||||
glRotatef(rollRotation, 0.0f, 1.0f, 0.0f); //roll the iris or correct roll about the lookat vector
|
||||
}
|
||||
|
@ -479,21 +545,21 @@ void Head::renderEyeBalls() {
|
|||
|
||||
//rotate the eyeball to aim towards the lookat position
|
||||
glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _rightEyePosition);
|
||||
glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP);
|
||||
float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP);
|
||||
glm::vec3 rotationAxis = glm::cross(targetLookatAxis, AVATAR_UP);
|
||||
float angle = 180.0f - angleBetween(targetLookatAxis, AVATAR_UP);
|
||||
glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
||||
glRotatef(180.0f, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations
|
||||
|
||||
} else {
|
||||
|
||||
//rotate the eyeball to aim straight ahead
|
||||
glm::vec3 rotationAxisToHeadFront = glm::cross(_orientation.getFront(), IDENTITY_UP);
|
||||
float angleToHeadFront = 180.0f - angleBetween(_orientation.getFront(), IDENTITY_UP);
|
||||
glm::vec3 rotationAxisToHeadFront = glm::cross(front, AVATAR_UP);
|
||||
float angleToHeadFront = 180.0f - angleBetween(front, AVATAR_UP);
|
||||
glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z);
|
||||
|
||||
//set the amount of roll (for correction after previous rotations)
|
||||
float rollRotation = angleBetween(_orientation.getFront(), IDENTITY_FRONT);
|
||||
float dot = glm::dot(_orientation.getFront(), -IDENTITY_RIGHT);
|
||||
float rollRotation = angleBetween(front, AVATAR_FRONT);
|
||||
float dot = glm::dot(front, -AVATAR_RIGHT);
|
||||
if ( dot < 0.0f ) { rollRotation = -rollRotation; }
|
||||
glRotatef(rollRotation, 0.0f, 1.0f, 0.0f); //roll the iris or correct roll about the lookat vector
|
||||
}
|
||||
|
@ -526,7 +592,12 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi
|
|||
}
|
||||
|
||||
|
||||
void Head::updateHair(float deltaTime) {
|
||||
void Head::updateHairPhysics(float deltaTime) {
|
||||
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::vec3 right = orientation * AVATAR_RIGHT;
|
||||
glm::vec3 up = orientation * AVATAR_UP;
|
||||
glm::vec3 front = orientation * AVATAR_FRONT;
|
||||
|
||||
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
|
||||
|
||||
|
@ -536,8 +607,8 @@ void Head::updateHair(float deltaTime) {
|
|||
|
||||
float radian = angle * PI_OVER_180;
|
||||
glm::vec3 baseDirection
|
||||
= _orientation.getFront() * sinf(radian)
|
||||
+ _orientation.getUp() * cosf(radian);
|
||||
= front * sinf(radian)
|
||||
+ up * cosf(radian);
|
||||
|
||||
_hairTuft[t].basePosition = _position + _scale * 0.9f * baseDirection;
|
||||
|
||||
|
@ -553,13 +624,13 @@ void Head::updateHair(float deltaTime) {
|
|||
if (midLength > 0.0f) {
|
||||
midDirection = midAxis / midLength;
|
||||
} else {
|
||||
midDirection = _orientation.getUp();
|
||||
midDirection = up;
|
||||
}
|
||||
|
||||
if (endLength > 0.0f) {
|
||||
endDirection = endAxis / endLength;
|
||||
} else {
|
||||
endDirection = _orientation.getUp();
|
||||
endDirection = up;
|
||||
}
|
||||
|
||||
// add spring force
|
||||
|
@ -604,13 +675,13 @@ void Head::updateHair(float deltaTime) {
|
|||
if (newMidLength > 0.0f) {
|
||||
newMidDirection = newMidVector/newMidLength;
|
||||
} else {
|
||||
newMidDirection = _orientation.getUp();
|
||||
newMidDirection = up;
|
||||
}
|
||||
|
||||
if (newEndLength > 0.0f) {
|
||||
newEndDirection = newEndVector/newEndLength;
|
||||
} else {
|
||||
newEndDirection = _orientation.getUp();
|
||||
newEndDirection = up;
|
||||
}
|
||||
|
||||
_hairTuft[t].endPosition = _hairTuft[t].midPosition + newEndDirection * _hairTuft[t].length * ONE_HALF;
|
||||
|
@ -618,41 +689,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "world.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "SerialInterface.h"
|
||||
#include "Orientation.h"
|
||||
#include <SharedUtil.h>
|
||||
|
||||
enum eyeContactTargets
|
||||
|
@ -25,7 +24,6 @@ enum eyeContactTargets
|
|||
};
|
||||
|
||||
const int NUM_HAIR_TUFTS = 4;
|
||||
const int NUM_HAIR_SEGMENTS = 4;
|
||||
|
||||
class Avatar;
|
||||
|
||||
|
@ -35,8 +33,8 @@ public:
|
|||
|
||||
void reset();
|
||||
void simulate(float deltaTime, bool isMine);
|
||||
void render(bool lookingInMirror, glm::vec3 cameraPosition);
|
||||
void renderMohawk(bool lookingInMirror);
|
||||
void render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha);
|
||||
void renderMohawk(glm::vec3 cameraPosition);
|
||||
|
||||
void setScale (float scale ) { _scale = scale; }
|
||||
void setPosition (glm::vec3 position ) { _position = position; }
|
||||
|
@ -45,10 +43,16 @@ public:
|
|||
void setSkinColor (glm::vec3 skinColor ) { _skinColor = skinColor; }
|
||||
void setSpringScale (float returnSpringScale ) { _returnSpringScale = returnSpringScale; }
|
||||
void setAverageLoudness(float averageLoudness ) { _averageLoudness = averageLoudness; }
|
||||
void setAudioLoudness (float audioLoudness ) { _audioLoudness = audioLoudness; }
|
||||
void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; }
|
||||
void setRenderLookatVectors(bool onOff ) { _renderLookatVectors = onOff; }
|
||||
|
||||
|
||||
glm::quat getOrientation() const;
|
||||
glm::quat getWorldAlignedOrientation () const;
|
||||
|
||||
glm::vec3 getRightDirection() const { return getOrientation() * AVATAR_RIGHT; }
|
||||
glm::vec3 getUpDirection () const { return getOrientation() * AVATAR_UP; }
|
||||
glm::vec3 getFrontDirection() const { return getOrientation() * AVATAR_FRONT; }
|
||||
|
||||
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||
float getAverageLoudness() {return _averageLoudness;};
|
||||
glm::vec3 caclulateAverageEyePosition() { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; }
|
||||
|
@ -73,8 +77,8 @@ private:
|
|||
glm::vec3 endVelocity;
|
||||
};
|
||||
|
||||
float _renderAlpha;
|
||||
bool _returnHeadToCenter;
|
||||
float _audioLoudness;
|
||||
glm::vec3 _skinColor;
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _rotation;
|
||||
|
@ -93,8 +97,8 @@ private:
|
|||
float _averageLoudness;
|
||||
float _audioAttack;
|
||||
float _returnSpringScale; //strength of return springs
|
||||
Orientation _orientation;
|
||||
glm::vec3 _bodyRotation;
|
||||
bool _lookingInMirror;
|
||||
bool _renderLookatVectors;
|
||||
HairTuft _hairTuft[NUM_HAIR_TUFTS];
|
||||
glm::vec3* _mohawkTriangleFan;
|
||||
|
@ -108,10 +112,10 @@ private:
|
|||
void renderEars();
|
||||
void renderMouth();
|
||||
void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
|
||||
void calculateGeometry( bool lookingInMirror);
|
||||
void calculateGeometry();
|
||||
void determineIfLookingAtSomething();
|
||||
void updateHair(float deltaTime);
|
||||
void renderHair(glm::vec3 cameraPosition);
|
||||
void resetHairPhysics();
|
||||
void updateHairPhysics(float deltaTime);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,9 +38,11 @@ void OculusManager::connect() {
|
|||
}
|
||||
|
||||
void OculusManager::updateYawOffset() {
|
||||
#ifdef __APPLE__
|
||||
float yaw, pitch, roll;
|
||||
_sensorFusion.GetOrientation().GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||
_yawOffset = yaw;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||
|
|
135
interface/src/Skeleton.cpp
Normal file
135
interface/src/Skeleton.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
//
|
||||
// Skeleton.cpp
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include "Skeleton.h"
|
||||
|
||||
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f;
|
||||
const float FLOATING_HEIGHT = 0.13f;
|
||||
|
||||
Skeleton::Skeleton() {
|
||||
}
|
||||
|
||||
void Skeleton::initialize() {
|
||||
|
||||
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
|
||||
joint[b].parent = AVATAR_JOINT_NULL;
|
||||
joint[b].position = glm::vec3(0.0, 0.0, 0.0);
|
||||
joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0);
|
||||
joint[b].rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
joint[b].length = 0.0;
|
||||
}
|
||||
|
||||
// specify the parental hierarchy
|
||||
joint[ AVATAR_JOINT_PELVIS ].parent = AVATAR_JOINT_NULL;
|
||||
joint[ AVATAR_JOINT_TORSO ].parent = AVATAR_JOINT_PELVIS;
|
||||
joint[ AVATAR_JOINT_CHEST ].parent = AVATAR_JOINT_TORSO;
|
||||
joint[ AVATAR_JOINT_NECK_BASE ].parent = AVATAR_JOINT_CHEST;
|
||||
joint[ AVATAR_JOINT_HEAD_BASE ].parent = AVATAR_JOINT_NECK_BASE;
|
||||
joint[ AVATAR_JOINT_HEAD_TOP ].parent = AVATAR_JOINT_HEAD_BASE;
|
||||
joint[ AVATAR_JOINT_LEFT_COLLAR ].parent = AVATAR_JOINT_CHEST;
|
||||
joint[ AVATAR_JOINT_LEFT_SHOULDER ].parent = AVATAR_JOINT_LEFT_COLLAR;
|
||||
joint[ AVATAR_JOINT_LEFT_ELBOW ].parent = AVATAR_JOINT_LEFT_SHOULDER;
|
||||
joint[ AVATAR_JOINT_LEFT_WRIST ].parent = AVATAR_JOINT_LEFT_ELBOW;
|
||||
joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].parent = AVATAR_JOINT_LEFT_WRIST;
|
||||
joint[ AVATAR_JOINT_RIGHT_COLLAR ].parent = AVATAR_JOINT_CHEST;
|
||||
joint[ AVATAR_JOINT_RIGHT_SHOULDER ].parent = AVATAR_JOINT_RIGHT_COLLAR;
|
||||
joint[ AVATAR_JOINT_RIGHT_ELBOW ].parent = AVATAR_JOINT_RIGHT_SHOULDER;
|
||||
joint[ AVATAR_JOINT_RIGHT_WRIST ].parent = AVATAR_JOINT_RIGHT_ELBOW;
|
||||
joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].parent = AVATAR_JOINT_RIGHT_WRIST;
|
||||
joint[ AVATAR_JOINT_LEFT_HIP ].parent = AVATAR_JOINT_PELVIS;
|
||||
joint[ AVATAR_JOINT_LEFT_KNEE ].parent = AVATAR_JOINT_LEFT_HIP;
|
||||
joint[ AVATAR_JOINT_LEFT_HEEL ].parent = AVATAR_JOINT_LEFT_KNEE;
|
||||
joint[ AVATAR_JOINT_LEFT_TOES ].parent = AVATAR_JOINT_LEFT_HEEL;
|
||||
joint[ AVATAR_JOINT_RIGHT_HIP ].parent = AVATAR_JOINT_PELVIS;
|
||||
joint[ AVATAR_JOINT_RIGHT_KNEE ].parent = AVATAR_JOINT_RIGHT_HIP;
|
||||
joint[ AVATAR_JOINT_RIGHT_HEEL ].parent = AVATAR_JOINT_RIGHT_KNEE;
|
||||
joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL;
|
||||
|
||||
// specify the default pose position
|
||||
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.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 );
|
||||
joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 );
|
||||
joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 );
|
||||
joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 );
|
||||
|
||||
joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, 0.01 );
|
||||
joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.01 );
|
||||
joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 );
|
||||
joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 );
|
||||
joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 );
|
||||
|
||||
joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.02 );
|
||||
joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.01, -0.25, -0.03 );
|
||||
joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.01, -0.22, 0.08 );
|
||||
joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 );
|
||||
|
||||
joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.02 );
|
||||
joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( -0.01, -0.25, -0.03 );
|
||||
joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 );
|
||||
joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 );
|
||||
|
||||
// calculate bone length
|
||||
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
|
||||
joint[b].length = glm::length(joint[b].defaultPosePosition);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate positions and rotations of all bones by traversing the skeleton tree:
|
||||
void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 position) {
|
||||
|
||||
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
|
||||
if (joint[b].parent == AVATAR_JOINT_NULL) {
|
||||
joint[b].rotation = orientation;
|
||||
joint[b].position = position;
|
||||
}
|
||||
else {
|
||||
joint[b].rotation = joint[ joint[b].parent ].rotation;
|
||||
joint[b].position = joint[ joint[b].parent ].position;
|
||||
}
|
||||
|
||||
glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].defaultPosePosition;
|
||||
joint[b].position += rotatedJointVector;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Skeleton::getArmLength() {
|
||||
return joint[ AVATAR_JOINT_RIGHT_ELBOW ].length
|
||||
+ joint[ AVATAR_JOINT_RIGHT_WRIST ].length
|
||||
+ joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].length;
|
||||
}
|
||||
|
||||
float Skeleton::getHeight() {
|
||||
return
|
||||
joint[ AVATAR_JOINT_LEFT_HEEL ].length +
|
||||
joint[ AVATAR_JOINT_LEFT_KNEE ].length +
|
||||
joint[ AVATAR_JOINT_PELVIS ].length +
|
||||
joint[ AVATAR_JOINT_TORSO ].length +
|
||||
joint[ AVATAR_JOINT_CHEST ].length +
|
||||
joint[ AVATAR_JOINT_NECK_BASE ].length +
|
||||
joint[ AVATAR_JOINT_HEAD_BASE ].length;
|
||||
}
|
||||
|
||||
float Skeleton::getPelvisStandingHeight() {
|
||||
return joint[ AVATAR_JOINT_LEFT_HEEL ].length +
|
||||
joint[ AVATAR_JOINT_LEFT_KNEE ].length;
|
||||
}
|
||||
|
||||
float Skeleton::getPelvisFloatingHeight() {
|
||||
return joint[ AVATAR_JOINT_LEFT_HEEL ].length +
|
||||
joint[ AVATAR_JOINT_LEFT_KNEE ].length +
|
||||
FLOATING_HEIGHT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
72
interface/src/Skeleton.h
Normal file
72
interface/src/Skeleton.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// Skeleton.h
|
||||
// interface
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef hifi_Skeleton_h
|
||||
#define hifi_Skeleton_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
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 update(float deltaTime, const glm::quat&, glm::vec3 position);
|
||||
void render();
|
||||
|
||||
float getArmLength();
|
||||
float getHeight();
|
||||
float getPelvisStandingHeight();
|
||||
float getPelvisFloatingHeight();
|
||||
//glm::vec3 getJointVectorFromParent(AvatarJointID jointID) {return joint[jointID].position - joint[joint[jointID].parent].position; }
|
||||
|
||||
struct AvatarJoint
|
||||
{
|
||||
AvatarJointID parent; // which joint is this joint connected to?
|
||||
glm::vec3 position; // the position at the "end" of the joint - in global space
|
||||
glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the default pose
|
||||
glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion
|
||||
float length; // the length of vector between the joint and its parent
|
||||
};
|
||||
|
||||
AvatarJoint joint[ NUM_AVATAR_JOINTS ];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -20,11 +20,25 @@ Transmitter::Transmitter() :
|
|||
_isConnected(false),
|
||||
_lastRotationRate(0,0,0),
|
||||
_lastAcceleration(0,0,0),
|
||||
_estimatedRotation(0,0,0)
|
||||
_estimatedRotation(0,0,0),
|
||||
_lastReceivedPacket(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Transmitter::checkForLostTransmitter() {
|
||||
// If we are in motion, check for loss of transmitter packets
|
||||
if (glm::length(_estimatedRotation) > 0.f) {
|
||||
timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
const int TIME_TO_ASSUME_LOST_MSECS = 2000;
|
||||
int msecsSinceLast = diffclock(_lastReceivedPacket, &now);
|
||||
if (msecsSinceLast > TIME_TO_ASSUME_LOST_MSECS) {
|
||||
resetLevels();
|
||||
printLog("Transmitter signal lost.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
void Transmitter::resetLevels() {
|
||||
_lastRotationRate *= 0.f;
|
||||
_estimatedRotation *= 0.f;
|
||||
|
@ -34,6 +48,11 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
|
|||
const int PACKET_HEADER_SIZE = 1; // Packet's first byte is 'T'
|
||||
const int ROTATION_MARKER_SIZE = 1; // 'R' = Rotation (clockwise about x,y,z)
|
||||
const int ACCELERATION_MARKER_SIZE = 1; // 'A' = Acceleration (x,y,z)
|
||||
if (!_lastReceivedPacket) {
|
||||
_lastReceivedPacket = new timeval;
|
||||
}
|
||||
gettimeofday(_lastReceivedPacket, NULL);
|
||||
|
||||
if (numBytes == PACKET_HEADER_SIZE + ROTATION_MARKER_SIZE + ACCELERATION_MARKER_SIZE
|
||||
+ sizeof(_lastRotationRate) + sizeof(_lastAcceleration)
|
||||
+ sizeof(_touchState.x) + sizeof(_touchState.y) + sizeof(_touchState.state)) {
|
||||
|
@ -69,12 +88,12 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
|
|||
_estimatedRotation.y *= (1.f - DECAY_RATE * DELTA_TIME);
|
||||
|
||||
if (!_isConnected) {
|
||||
printf("Transmitter V2 Connected.\n");
|
||||
printLog("Transmitter Connected.\n");
|
||||
_isConnected = true;
|
||||
_estimatedRotation *= 0.0;
|
||||
}
|
||||
} else {
|
||||
printf("Transmitter V2 packet read error, %d bytes.\n", numBytes);
|
||||
printLog("Transmitter packet read error, %d bytes.\n", numBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class Transmitter
|
|||
public:
|
||||
Transmitter();
|
||||
void render();
|
||||
void checkForLostTransmitter();
|
||||
void resetLevels();
|
||||
void renderLevels(int width, int height);
|
||||
bool isConnected() { return _isConnected; };
|
||||
|
@ -41,6 +42,7 @@ private:
|
|||
glm::vec3 _lastAcceleration;
|
||||
glm::vec3 _estimatedRotation;
|
||||
TouchState _touchState;
|
||||
timeval* _lastReceivedPacket;
|
||||
|
||||
#endif /* defined(__hifi__Transmitter__) */
|
||||
};
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/noise.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <AvatarData.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Log.h"
|
||||
|
@ -71,6 +72,65 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
|||
return acos((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))) * 180.f / PI;
|
||||
}
|
||||
|
||||
// Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's
|
||||
// http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde,
|
||||
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
|
||||
glm::vec3 safeEulerAngles(const glm::quat& q) {
|
||||
float sy = 2.0f * (q.y * q.w - q.x * q.z);
|
||||
if (sy < 1.0f - EPSILON) {
|
||||
if (sy > -1.0f + EPSILON) {
|
||||
return glm::degrees(glm::vec3(
|
||||
atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)),
|
||||
asinf(sy),
|
||||
atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))));
|
||||
|
||||
} else {
|
||||
// not a unique solution; x + z = atan2(-m21, m11)
|
||||
return glm::degrees(glm::vec3(
|
||||
0.0f,
|
||||
PIf * -0.5f,
|
||||
atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))));
|
||||
}
|
||||
} else {
|
||||
// not a unique solution; x - z = atan2(-m21, m11)
|
||||
return glm::degrees(glm::vec3(
|
||||
0.0f,
|
||||
PIf * 0.5f,
|
||||
-atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))));
|
||||
}
|
||||
}
|
||||
|
||||
// Safe version of glm::mix; based on the code in Nick Bobick's article,
|
||||
// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
|
||||
// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java)
|
||||
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) {
|
||||
float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
|
||||
float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1;
|
||||
|
||||
// adjust signs if necessary
|
||||
if (cosa < 0.0f) {
|
||||
cosa = -cosa;
|
||||
ox = -ox;
|
||||
oy = -oy;
|
||||
oz = -oz;
|
||||
ow = -ow;
|
||||
}
|
||||
|
||||
// calculate coefficients; if the angle is too close to zero, we must fall back
|
||||
// to linear interpolation
|
||||
if ((1.0f - cosa) > EPSILON) {
|
||||
float angle = acosf(cosa), sina = sinf(angle);
|
||||
s0 = sinf((1.0f - proportion) * angle) / sina;
|
||||
s1 = sinf(proportion * angle) / sina;
|
||||
|
||||
} else {
|
||||
s0 = 1.0f - proportion;
|
||||
s1 = proportion;
|
||||
}
|
||||
|
||||
return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz));
|
||||
}
|
||||
|
||||
// Draw a 3D vector floating in space
|
||||
void drawVector(glm::vec3 * vector) {
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -333,10 +393,10 @@ void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int
|
|||
}
|
||||
|
||||
|
||||
void renderOrientationDirections(glm::vec3 position, Orientation orientation, float size) {
|
||||
glm::vec3 pRight = position + orientation.getRight() * size;
|
||||
glm::vec3 pUp = position + orientation.getUp () * size;
|
||||
glm::vec3 pFront = position + orientation.getFront() * size;
|
||||
void renderOrientationDirections(glm::vec3 position, const glm::quat& orientation, float size) {
|
||||
glm::vec3 pRight = position + orientation * AVATAR_RIGHT * size;
|
||||
glm::vec3 pUp = position + orientation * AVATAR_UP * size;
|
||||
glm::vec3 pFront = position + orientation * AVATAR_FRONT * size;
|
||||
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
@ -364,126 +424,5 @@ bool closeEnoughForGovernmentWork(float a, float b) {
|
|||
}
|
||||
|
||||
|
||||
void testOrientationClass() {
|
||||
printLog("\n----------\ntestOrientationClass()\n----------\n\n");
|
||||
|
||||
oTestCase tests[] = {
|
||||
// - inputs ------------, outputs -------------------- ------------------- ----------------------------
|
||||
// -- front -------------------, -- up -------------, -- right -------------------
|
||||
// ( yaw , pitch, roll , front.x , front.y , front.z , up.x , up.y , up.z , right.x , right.y , right.z )
|
||||
|
||||
// simple yaw tests
|
||||
oTestCase( 0.f , 0.f , 0.f , 0.f , 0.f , 1.0f , 0.f , 1.0f , 0.f , -1.0f , 0.f , 0.f ),
|
||||
oTestCase(45.0f , 0.f , 0.f , 0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , 0.707107f),
|
||||
oTestCase( 90.0f, 0.f , 0.f , 1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , 1.0f ),
|
||||
oTestCase(135.0f, 0.f , 0.f , 0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , 0.707107f),
|
||||
oTestCase(180.0f, 0.f , 0.f , 0.f , 0.f , -1.0f , 0.f , 1.0f , 0.f , 1.0f , 0.f , 0.f ),
|
||||
oTestCase(225.0f, 0.f , 0.f , -0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , -0.707107f),
|
||||
oTestCase(270.0f, 0.f , 0.f , -1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , -1.0f ),
|
||||
oTestCase(315.0f, 0.f , 0.f , -0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , -0.707107f),
|
||||
oTestCase(-45.0f, 0.f , 0.f , -0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , -0.707107f),
|
||||
oTestCase(-90.0f, 0.f , 0.f , -1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , -1.0f ),
|
||||
oTestCase(-135.0f,0.f , 0.f , -0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , -0.707107f),
|
||||
oTestCase(-180.0f,0.f , 0.f , 0.f , 0.f , -1.0f , 0.f , 1.0f , 0.f , 1.0f , 0.f , 0.f ),
|
||||
oTestCase(-225.0f,0.f , 0.f , 0.707107f , 0.f ,-0.707107f , 0.f , 1.0f , 0.f , 0.707107f, 0.f , 0.707107f),
|
||||
oTestCase(-270.0f,0.f , 0.f , 1.0f , 0.f , 0.f , 0.f , 1.0f , 0.f , 0.0f , 0.f , 1.0f ),
|
||||
oTestCase(-315.0f,0.f , 0.f , 0.707107f , 0.f , 0.707107f , 0.f , 1.0f , 0.f , -0.707107f, 0.f , 0.707107f),
|
||||
|
||||
// simple pitch tests
|
||||
oTestCase( 0.f , 0.f , 0.f , 0.f, 0.f , 1.0f , 0.f , 1.0f , 0.f , -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,45.0f , 0.f , 0.f, 0.707107f , 0.707107f, 0.f ,0.707107f, -0.707107f, -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,90.f , 0.f , 0.f, 1.0f , 0.0f , 0.f ,0.0f , -1.0f , -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,135.0f, 0.f , 0.f, 0.707107f , -0.707107f, 0.f ,-0.707107f, -0.707107f, -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,180.f , 0.f , 0.f, 0.0f ,-1.0f , 0.f ,-1.0f , 0.f , -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,225.0f, 0.f , 0.f,-0.707107f , -0.707107f, 0.f ,-0.707107f, 0.707107f, -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,270.f , 0.f , 0.f,-1.0f , 0.0f , 0.f ,0.0f , 1.0f , -1.0f , 0.f , 0.f ),
|
||||
oTestCase( 0.f ,315.0f, 0.f , 0.f,-0.707107f , 0.707107f, 0.f , 0.707107f, 0.707107f, -1.0f , 0.f , 0.f ),
|
||||
|
||||
// simple roll tests
|
||||
oTestCase( 0.f , 0.f , 0.f , 0.f , 0.f , 1.0f , 0.f , 1.0f ,0.0f , -1.0f , 0.f , 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,45.0f , 0.f , 0.f , 1.0f , 0.707107f , 0.707107f ,0.0f , -0.707107f, 0.707107f, 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,90.f , 0.f , 0.f , 1.0f , 1.0f , 0.0f ,0.0f , 0.0f , 1.0f , 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,135.0f , 0.f , 0.f , 1.0f , 0.707107f , -0.707107f,0.0f , 0.707107f , 0.707107f, 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,180.f , 0.f , 0.f , 1.0f , 0.0f , -1.0f ,0.0f , 1.0f , 0.0f , 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,225.0f , 0.f , 0.f , 1.0f , -0.707107f, -0.707107f,0.0f , 0.707107f ,-0.707107f, 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,270.f , 0.f , 0.f , 1.0f , -1.0f , 0.0f ,0.0f , 0.0f , -1.0f , 0.0f ),
|
||||
oTestCase( 0.f , 0.f ,315.0f , 0.f , 0.f , 1.0f , -0.707107f, 0.707107f ,0.0f , -0.707107f,-0.707107f, 0.0f ),
|
||||
|
||||
// yaw combo tests
|
||||
oTestCase( 90.f , 90.f , 0.f , 0.f , 1.0f , 0.0f , -1.0f , 0.0f , 0.f , 0.0f , 0.f , 1.0f ),
|
||||
oTestCase( 90.f , 0.f , 90.f , 1.0f , 0.0f, 0.f , 0.0f , 0.0f , -1.f , 0.0f , 1.0f , 0.0f ),
|
||||
};
|
||||
|
||||
int failedCount = 0;
|
||||
int totalTests = sizeof(tests)/sizeof(oTestCase);
|
||||
|
||||
for (int i=0; i < totalTests; i++) {
|
||||
|
||||
bool passed = true; // I'm an optimist!
|
||||
|
||||
float yaw = tests[i].yaw;
|
||||
float pitch = tests[i].pitch;
|
||||
float roll = tests[i].roll;
|
||||
|
||||
Orientation o1;
|
||||
o1.setToIdentity();
|
||||
o1.yaw(yaw);
|
||||
o1.pitch(pitch);
|
||||
o1.roll(roll);
|
||||
|
||||
glm::vec3 front = o1.getFront();
|
||||
glm::vec3 up = o1.getUp();
|
||||
glm::vec3 right = o1.getRight();
|
||||
|
||||
printLog("\n-----\nTest: %d - yaw=%f , pitch=%f , roll=%f \n",i+1,yaw,pitch,roll);
|
||||
|
||||
printLog("\nFRONT\n");
|
||||
printLog(" + received: front.x=%f, front.y=%f, front.z=%f\n",front.x,front.y,front.z);
|
||||
|
||||
if (closeEnoughForGovernmentWork(front.x, tests[i].frontX)
|
||||
&& closeEnoughForGovernmentWork(front.y, tests[i].frontY)
|
||||
&& closeEnoughForGovernmentWork(front.z, tests[i].frontZ)) {
|
||||
printLog(" front vector PASSES!\n");
|
||||
} else {
|
||||
printLog(" expected: front.x=%f, front.y=%f, front.z=%f\n",tests[i].frontX,tests[i].frontY,tests[i].frontZ);
|
||||
printLog(" front vector FAILED! \n");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
printLog("\nUP\n");
|
||||
printLog(" + received: up.x=%f, up.y=%f, up.z=%f\n",up.x,up.y,up.z);
|
||||
if (closeEnoughForGovernmentWork(up.x, tests[i].upX)
|
||||
&& closeEnoughForGovernmentWork(up.y, tests[i].upY)
|
||||
&& closeEnoughForGovernmentWork(up.z, tests[i].upZ)) {
|
||||
printLog(" up vector PASSES!\n");
|
||||
} else {
|
||||
printLog(" expected: up.x=%f, up.y=%f, up.z=%f\n",tests[i].upX,tests[i].upY,tests[i].upZ);
|
||||
printLog(" up vector FAILED!\n");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
|
||||
printLog("\nRIGHT\n");
|
||||
printLog(" + received: right.x=%f, right.y=%f, right.z=%f\n",right.x,right.y,right.z);
|
||||
if (closeEnoughForGovernmentWork(right.x, tests[i].rightX)
|
||||
&& closeEnoughForGovernmentWork(right.y, tests[i].rightY)
|
||||
&& closeEnoughForGovernmentWork(right.z, tests[i].rightZ)) {
|
||||
printLog(" right vector PASSES!\n");
|
||||
} else {
|
||||
printLog(" expected: right.x=%f, right.y=%f, right.z=%f\n",tests[i].rightX,tests[i].rightY,tests[i].rightZ);
|
||||
printLog(" right vector FAILED!\n");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
if (!passed) {
|
||||
printLog("\n-----\nTest: %d - FAILED! \n----------\n\n",i+1);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
printLog("\n-----\nTotal Failed: %d out of %d \n----------\n\n",failedCount,totalTests);
|
||||
printLog("\n----------DONE----------\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#endif
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <Orientation.h>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
// the standard sans serif font family
|
||||
#define SANS_FONT_FAMILY "Helvetica"
|
||||
|
@ -46,50 +45,19 @@ void drawVector(glm::vec3* vector);
|
|||
|
||||
float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
|
||||
|
||||
glm::vec3 safeEulerAngles(const glm::quat& q);
|
||||
|
||||
glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
|
||||
|
||||
double diffclock(timeval *clock1,timeval *clock2);
|
||||
|
||||
void drawGroundPlaneGrid(float size);
|
||||
|
||||
void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness);
|
||||
|
||||
void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size );
|
||||
void renderOrientationDirections( glm::vec3 position, const glm::quat& orientation, float size );
|
||||
|
||||
void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::vec3 cameraPosition);
|
||||
void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int numSides );
|
||||
|
||||
|
||||
class oTestCase {
|
||||
public:
|
||||
float yaw;
|
||||
float pitch;
|
||||
float roll;
|
||||
|
||||
float frontX;
|
||||
float frontY;
|
||||
float frontZ;
|
||||
|
||||
float upX;
|
||||
float upY;
|
||||
float upZ;
|
||||
|
||||
float rightX;
|
||||
float rightY;
|
||||
float rightZ;
|
||||
|
||||
oTestCase(
|
||||
float yaw, float pitch, float roll,
|
||||
float frontX, float frontY, float frontZ,
|
||||
float upX, float upY, float upZ,
|
||||
float rightX, float rightY, float rightZ
|
||||
) :
|
||||
yaw(yaw),pitch(pitch),roll(roll),
|
||||
frontX(frontX),frontY(frontY),frontZ(frontZ),
|
||||
upX(upX),upY(upY),upZ(upZ),
|
||||
rightX(rightX),rightY(rightY),rightZ(rightZ)
|
||||
{};
|
||||
};
|
||||
|
||||
|
||||
void testOrientationClass();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -887,11 +887,14 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
|
|||
|
||||
bool VoxelSystem::isViewChanging() {
|
||||
bool result = false; // assume the best
|
||||
|
||||
/** TEMPORARY HACK ******
|
||||
// If our viewFrustum has changed since our _lastKnowViewFrustum
|
||||
if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) {
|
||||
result = true;
|
||||
_lastKnowViewFrustum = *_viewFrustum; // save last known
|
||||
}
|
||||
**/
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
const float WORLD_SIZE = 10.0;
|
||||
#define PI 3.14159265
|
||||
#define PIf 3.14159265f
|
||||
#define GRAVITY_EARTH 9.80665f;
|
||||
|
||||
const float GRAVITY_EARTH = 9.80665f;
|
||||
const float EDGE_SIZE_GROUND_PLANE = 20.f;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,7 +58,11 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) {
|
|||
|
||||
// if we don't have an explicit destination socket then pull active socket for current audio mixer from agent list
|
||||
if (!_isDestinationSocketExplicit) {
|
||||
_destinationSocket = *AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER)->getActiveSocket();
|
||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
|
||||
if (audioMixer) {
|
||||
_destinationSocket = *audioMixer->getActiveSocket();
|
||||
}
|
||||
}
|
||||
|
||||
injector->injectAudio(_injectorSocket, &_destinationSocket);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
|
@ -56,7 +57,12 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
memcpy(&_bearing, dataBuffer, sizeof(float));
|
||||
dataBuffer += sizeof(_bearing);
|
||||
|
||||
if (_bearing > 180 || _bearing < -180) {
|
||||
// if this agent sent us a NaN bearing then don't consider this good audio and bail
|
||||
if (std::isnan(_bearing)) {
|
||||
_endOfLastWrite = _nextOutput = _buffer;
|
||||
_started = false;
|
||||
return 0;
|
||||
} else if (_bearing > 180 || _bearing < -180) {
|
||||
// we were passed an invalid bearing because this agent wants loopback (pressed the H key)
|
||||
_shouldLoopbackForAgent = true;
|
||||
|
||||
|
@ -66,7 +72,7 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
: _bearing + AGENT_LOOPBACK_MODIFIER;
|
||||
} else {
|
||||
_shouldLoopbackForAgent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we have enough bytes left for this to be the right amount of audio
|
||||
|
|
|
@ -23,7 +23,6 @@ AvatarData::AvatarData(Agent* owningAgent) :
|
|||
_bodyYaw(-90.0),
|
||||
_bodyPitch(0.0),
|
||||
_bodyRoll(0.0),
|
||||
_audioLoudness(0),
|
||||
_handState(0),
|
||||
_cameraPosition(0,0,0),
|
||||
_cameraOrientation(),
|
||||
|
@ -37,6 +36,7 @@ AvatarData::AvatarData(Agent* owningAgent) :
|
|||
_wantDelta(false),
|
||||
_headData(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AvatarData::~AvatarData() {
|
||||
|
@ -92,7 +92,12 @@ packVec3ToBytes(NULL, handPositionRelative, -1.0f , 1.0f, 4);
|
|||
destinationBuffer += sizeof(_headData->_lookAtPosition);
|
||||
|
||||
// Instantaneous audio loudness (used to drive facial animation)
|
||||
<<<<<<< HEAD
|
||||
destinationBuffer += packFloatToByte(destinationBuffer, std::min(MAX_AUDIO_LOUDNESS, _audioLoudness), MAX_AUDIO_LOUDNESS);
|
||||
=======
|
||||
memcpy(destinationBuffer, &_headData->_audioLoudness, sizeof(float));
|
||||
destinationBuffer += sizeof(float);
|
||||
>>>>>>> c7921c4be90dc45a82793845a9a55b77a3fb5a3f
|
||||
|
||||
// camera details
|
||||
memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition));
|
||||
|
@ -178,7 +183,9 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
sourceBuffer += sizeof(_headData->_lookAtPosition);
|
||||
|
||||
// Instantaneous audio loudness (used to drive facial animation)
|
||||
sourceBuffer += unpackFloatFromByte(sourceBuffer, _audioLoudness, MAX_AUDIO_LOUDNESS);
|
||||
//sourceBuffer += unpackFloatFromByte(sourceBuffer, _audioLoudness, MAX_AUDIO_LOUDNESS);
|
||||
memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float));
|
||||
sourceBuffer += sizeof(float);
|
||||
|
||||
// camera details
|
||||
memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition));
|
||||
|
|
|
@ -26,6 +26,11 @@ const int HAND_STATE_START_BIT = 5; // 6th and 7th bits
|
|||
const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation
|
||||
|
||||
|
||||
// this is where the coordinate system is represented
|
||||
const glm::vec3 AVATAR_RIGHT = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
const glm::vec3 AVATAR_UP = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
const glm::vec3 AVATAR_FRONT = glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
|
||||
enum KeyState
|
||||
{
|
||||
NO_KEY_DOWN = 0,
|
||||
|
@ -57,11 +62,7 @@ public:
|
|||
// Hand State
|
||||
void setHandState(char s) { _handState = s; };
|
||||
char getHandState() const {return _handState; };
|
||||
|
||||
// Instantaneous audio loudness to drive mouth/facial animation
|
||||
void setLoudness(float l) { _audioLoudness = l; };
|
||||
float getLoudness() const {return _audioLoudness; };
|
||||
|
||||
|
||||
// getters for camera details
|
||||
const glm::vec3& getCameraPosition() const { return _cameraPosition; };
|
||||
const glm::quat& getCameraOrientation() const { return _cameraOrientation; }
|
||||
|
@ -107,9 +108,6 @@ protected:
|
|||
float _bodyPitch;
|
||||
float _bodyRoll;
|
||||
|
||||
// Audio loudness (used to drive facial animation)
|
||||
float _audioLoudness;
|
||||
|
||||
// Hand state (are we grabbing something or not)
|
||||
char _handState;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ HeadData::HeadData(AvatarData* owningAvatar) :
|
|||
_lookAtPosition(0.0f, 0.0f, 0.0f),
|
||||
_leanSideways(0.0f),
|
||||
_leanForward(0.0f),
|
||||
_audioLoudness(0.0f),
|
||||
_owningAvatar(owningAvatar)
|
||||
{
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
float getRoll() const { return _roll; }
|
||||
void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
|
||||
|
||||
void setAudioLoudness(float audioLoudness) { _audioLoudness = audioLoudness; }
|
||||
|
||||
void addYaw(float yaw);
|
||||
void addPitch(float pitch);
|
||||
void addRoll(float roll);
|
||||
|
@ -57,6 +59,7 @@ protected:
|
|||
glm::vec3 _lookAtPosition;
|
||||
float _leanSideways;
|
||||
float _leanForward;
|
||||
float _audioLoudness;
|
||||
AvatarData* _owningAvatar;
|
||||
private:
|
||||
// privatize copy ctor and assignment operator so copies of this object cannot be made
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
//-----------------------------------------------------------
|
||||
//
|
||||
// Created by Jeffrey Ventrella
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
||||
#include "Orientation.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
static const bool USING_QUATERNIONS = true;
|
||||
|
||||
Orientation::Orientation() {
|
||||
setToIdentity();
|
||||
}
|
||||
|
||||
void Orientation::setToIdentity() {
|
||||
|
||||
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::yaw(float angle) {
|
||||
|
||||
float radian = angle * PI_OVER_180;
|
||||
|
||||
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) {
|
||||
|
||||
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) {
|
||||
|
||||
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 pitch_change, float yaw_change, float roll_change) {
|
||||
pitch(pitch_change);
|
||||
yaw (yaw_change);
|
||||
roll (roll_change);
|
||||
}
|
||||
|
||||
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::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);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
//-----------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
|
||||
#ifndef __interface__orientation__
|
||||
#define __interface__orientation__
|
||||
|
||||
#include <cmath>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
// 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
|
||||
{
|
||||
public:
|
||||
Orientation();
|
||||
|
||||
void set(Orientation);
|
||||
void setToIdentity();
|
||||
|
||||
void pitch(float pitch_change);
|
||||
void yaw (float yaw_change);
|
||||
void roll (float roll_change);
|
||||
|
||||
void rotate(float pitch, float yaw, float roll);
|
||||
void rotate(glm::vec3 EulerAngles);
|
||||
void rotate(glm::quat quaternion);
|
||||
|
||||
const glm::quat& getQuat() const {return quat;}
|
||||
|
||||
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 rotateAndGenerateDirections(glm::quat rotation);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -250,7 +250,8 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket
|
|||
|
||||
if (agent->getType() == AGENT_TYPE_AUDIO_MIXER ||
|
||||
agent->getType() == AGENT_TYPE_VOXEL ||
|
||||
agent->getType() == AGENT_TYPE_ANIMATION_SERVER) {
|
||||
agent->getType() == AGENT_TYPE_ANIMATION_SERVER ||
|
||||
agent->getType() == AGENT_TYPE_AUDIO_INJECTOR) {
|
||||
// until the Audio class also uses our agentList, we need to update
|
||||
// the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
|
||||
agent->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define __hifi__SharedUtil__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "SharedUtil.h"
|
||||
|
||||
#include "AABox.h"
|
||||
#include "GeometryUtil.h"
|
||||
|
||||
|
||||
void AABox::scale(float scale) {
|
||||
|
@ -82,6 +83,17 @@ bool AABox::contains(const glm::vec3& point) const {
|
|||
isWithin(point.z, _corner.z, _size.z);
|
||||
}
|
||||
|
||||
// determines whether a value is within the expanded extents
|
||||
static bool isWithinExpanded(float value, float corner, float size, float expansion) {
|
||||
return value >= corner - expansion && value <= corner + size + expansion;
|
||||
}
|
||||
|
||||
bool AABox::expandedContains(const glm::vec3& point, float expansion) const {
|
||||
return isWithinExpanded(point.x, _corner.x, _size.x, expansion) &&
|
||||
isWithinExpanded(point.y, _corner.y, _size.y, expansion) &&
|
||||
isWithinExpanded(point.z, _corner.z, _size.z, expansion);
|
||||
}
|
||||
|
||||
// finds the intersection between a ray and the facing plane on one axis
|
||||
static bool findIntersection(float origin, float direction, float corner, float size, float& distance) {
|
||||
if (direction > EPSILON) {
|
||||
|
@ -95,6 +107,30 @@ static bool findIntersection(float origin, float direction, float corner, float
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const {
|
||||
// handle the trivial cases where the expanded box contains the start or end
|
||||
if (expandedContains(start, expansion) || expandedContains(end, expansion)) {
|
||||
return true;
|
||||
}
|
||||
// check each axis
|
||||
glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion);
|
||||
glm::vec3 expandedSize = _size + glm::vec3(expansion, expansion, expansion) * 2.0f;
|
||||
glm::vec3 direction = end - start;
|
||||
float axisDistance;
|
||||
return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) &&
|
||||
axisDistance >= 0.0f && axisDistance <= 1.0f &&
|
||||
isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) &&
|
||||
isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) ||
|
||||
(findIntersection(start.y, direction.y, expandedCorner.y, expandedSize.y, axisDistance) &&
|
||||
axisDistance >= 0.0f && axisDistance <= 1.0f &&
|
||||
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x) &&
|
||||
isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) ||
|
||||
(findIntersection(start.z, direction.z, expandedCorner.z, expandedSize.z, axisDistance) &&
|
||||
axisDistance >= 0.0f && axisDistance <= 1.0f &&
|
||||
isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) &&
|
||||
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x));
|
||||
}
|
||||
|
||||
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
|
||||
// handle the trivial case where the box contains the origin
|
||||
if (contains(origin)) {
|
||||
|
@ -126,3 +162,168 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
|
||||
glm::vec4 center4 = glm::vec4(center, 1.0f);
|
||||
|
||||
float minPenetrationLength = FLT_MAX;
|
||||
for (int i = 0; i < FACE_COUNT; i++) {
|
||||
glm::vec4 facePlane = getPlane((BoxFace)i);
|
||||
glm::vec3 vector = getClosestPointOnFace(center, (BoxFace)i) - center;
|
||||
if (glm::dot(center4, getPlane((BoxFace)i)) >= 0.0f) {
|
||||
// outside this face, so use vector to closest point to determine penetration
|
||||
return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration);
|
||||
}
|
||||
float vectorLength = glm::length(vector);
|
||||
if (vectorLength < minPenetrationLength) {
|
||||
// remember the smallest penetration vector; if we're inside all faces, we'll use that
|
||||
penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius :
|
||||
vector * ((vectorLength + radius) / -vectorLength);
|
||||
minPenetrationLength = vectorLength;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const {
|
||||
glm::vec4 start4 = glm::vec4(start, 1.0f);
|
||||
glm::vec4 end4 = glm::vec4(end, 1.0f);
|
||||
glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);
|
||||
|
||||
float minPenetrationLength = FLT_MAX;
|
||||
for (int i = 0; i < FACE_COUNT; i++) {
|
||||
// find the vector from the segment to the closest point on the face (starting from deeper end)
|
||||
glm::vec4 facePlane = getPlane((BoxFace)i);
|
||||
glm::vec3 closest = (glm::dot(start4, facePlane) <= glm::dot(end4, facePlane)) ?
|
||||
getClosestPointOnFace(start4, startToEnd, (BoxFace)i) : getClosestPointOnFace(end4, -startToEnd, (BoxFace)i);
|
||||
glm::vec3 vector = -computeVectorFromPointToSegment(closest, start, end);
|
||||
if (glm::dot(vector, glm::vec3(facePlane)) < 0.0f) {
|
||||
// outside this face, so use vector to closest point to determine penetration
|
||||
return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration);
|
||||
}
|
||||
float vectorLength = glm::length(vector);
|
||||
if (vectorLength < minPenetrationLength) {
|
||||
// remember the smallest penetration vector; if we're inside all faces, we'll use that
|
||||
penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius :
|
||||
vector * ((vectorLength + radius) / -vectorLength);
|
||||
minPenetrationLength = vectorLength;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) const {
|
||||
switch (face) {
|
||||
case MIN_X_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
|
||||
case MAX_X_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x + _size.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
|
||||
case MIN_Y_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y, _corner.z + _size.z));
|
||||
|
||||
case MAX_Y_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _size.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
|
||||
case MIN_Z_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z));
|
||||
|
||||
case MAX_Z_FACE:
|
||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _size.z),
|
||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const {
|
||||
// check against the four planes that border the face
|
||||
BoxFace oppositeFace = getOppositeFace(face);
|
||||
bool anyOutside = false;
|
||||
for (int i = 0; i < FACE_COUNT; i++) {
|
||||
if (i == face || i == oppositeFace) {
|
||||
continue;
|
||||
}
|
||||
glm::vec4 iPlane = getPlane((BoxFace)i);
|
||||
float originDistance = glm::dot(origin, iPlane);
|
||||
if (originDistance < 0.0f) {
|
||||
continue; // inside the border
|
||||
}
|
||||
anyOutside = true;
|
||||
float divisor = glm::dot(direction, iPlane);
|
||||
if (fabs(divisor) < EPSILON) {
|
||||
continue; // segment is parallel to plane
|
||||
}
|
||||
// find intersection and see if it lies within face bounds
|
||||
float directionalDistance = -originDistance / divisor;
|
||||
glm::vec4 intersection = origin + direction * directionalDistance;
|
||||
BoxFace iOppositeFace = getOppositeFace((BoxFace)i);
|
||||
for (int j = 0; j < FACE_COUNT; j++) {
|
||||
if (j == face || j == oppositeFace || j == i || j == iOppositeFace) {
|
||||
continue;
|
||||
}
|
||||
if (glm::dot(intersection, getPlane((BoxFace)j)) > 0.0f) {
|
||||
goto outerContinue; // intersection is out of bounds
|
||||
}
|
||||
}
|
||||
return getClosestPointOnFace(glm::vec3(intersection), face);
|
||||
|
||||
outerContinue: ;
|
||||
}
|
||||
|
||||
// if we were outside any of the sides, we must check against the diagonals
|
||||
if (anyOutside) {
|
||||
int faceAxis = face / 2;
|
||||
int secondAxis = (faceAxis + 1) % 3;
|
||||
int thirdAxis = (faceAxis + 2) % 3;
|
||||
|
||||
glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));
|
||||
glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));
|
||||
glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
|
||||
|
||||
glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
|
||||
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _size) * 0.5f);
|
||||
glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
|
||||
secondAxisMaxPlane + thirdAxisMaxPlane + offset };
|
||||
|
||||
for (int i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {
|
||||
float divisor = glm::dot(direction, diagonals[i]);
|
||||
if (fabs(divisor) < EPSILON) {
|
||||
continue; // segment is parallel to diagonal plane
|
||||
}
|
||||
float directionalDistance = -glm::dot(origin, diagonals[i]) / divisor;
|
||||
return getClosestPointOnFace(glm::vec3(origin + direction * directionalDistance), face);
|
||||
}
|
||||
}
|
||||
|
||||
// last resort or all inside: clamp origin to face
|
||||
return getClosestPointOnFace(glm::vec3(origin), face);
|
||||
}
|
||||
|
||||
glm::vec4 AABox::getPlane(BoxFace face) const {
|
||||
switch (face) {
|
||||
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
|
||||
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _size.x);
|
||||
case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y);
|
||||
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _size.y);
|
||||
case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z);
|
||||
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _size.z);
|
||||
}
|
||||
}
|
||||
|
||||
BoxFace AABox::getOppositeFace(BoxFace face) {
|
||||
switch (face) {
|
||||
case MIN_X_FACE: return MAX_X_FACE;
|
||||
case MAX_X_FACE: return MIN_X_FACE;
|
||||
case MIN_Y_FACE: return MAX_Y_FACE;
|
||||
case MAX_Y_FACE: return MIN_Y_FACE;
|
||||
case MIN_Z_FACE: return MAX_Z_FACE;
|
||||
case MAX_Z_FACE: return MIN_Z_FACE;
|
||||
}
|
||||
}
|
||||
|
|
13
libraries/voxels/src/AABox.h
Executable file → Normal file
13
libraries/voxels/src/AABox.h
Executable file → Normal file
|
@ -22,6 +22,8 @@ enum BoxFace {
|
|||
MAX_Z_FACE
|
||||
};
|
||||
|
||||
const int FACE_COUNT = 6;
|
||||
|
||||
class AABox
|
||||
{
|
||||
|
||||
|
@ -46,9 +48,20 @@ public:
|
|||
const glm::vec3& getCenter() const { return _center; };
|
||||
|
||||
bool contains(const glm::vec3& point) const;
|
||||
bool expandedContains(const glm::vec3& point, float expansion) const;
|
||||
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
|
||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
|
||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||
|
||||
private:
|
||||
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
|
||||
glm::vec4 getPlane(BoxFace face) const;
|
||||
|
||||
static BoxFace getOppositeFace(BoxFace face);
|
||||
|
||||
glm::vec3 _corner;
|
||||
glm::vec3 _center;
|
||||
glm::vec3 _size;
|
||||
|
|
|
@ -5,12 +5,18 @@
|
|||
// Created by Andrzej Kapolka on 5/21/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "GeometryUtil.h"
|
||||
|
||||
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) {
|
||||
// compute the projection of the point vector onto the segment vector
|
||||
glm::vec3 segmentVector = end - start;
|
||||
float proj = glm::dot(point - start, segmentVector) / glm::dot(segmentVector, segmentVector);
|
||||
float lengthSquared = glm::dot(segmentVector, segmentVector);
|
||||
if (lengthSquared < EPSILON) {
|
||||
return start - point; // start and end the same
|
||||
}
|
||||
float proj = glm::dot(point - start, segmentVector) / lengthSquared;
|
||||
if (proj <= 0.0f) { // closest to the start
|
||||
return start - point;
|
||||
|
||||
|
@ -21,3 +27,91 @@ glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec
|
|||
return start + segmentVector*proj - point;
|
||||
}
|
||||
}
|
||||
|
||||
bool findSpherePenetration(const glm::vec3& penetratorToPenetratee, const glm::vec3& direction,
|
||||
float combinedRadius, glm::vec3& penetration) {
|
||||
float vectorLength = glm::length(penetratorToPenetratee);
|
||||
if (vectorLength < EPSILON) {
|
||||
penetration = direction * combinedRadius;
|
||||
return true;
|
||||
}
|
||||
float distance = vectorLength - combinedRadius;
|
||||
if (distance < 0.0f) {
|
||||
penetration = penetratorToPenetratee * (-distance / vectorLength);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findSpherePointPenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec3& penetrateeLocation, glm::vec3& penetration) {
|
||||
return findSpherePenetration(penetrateeLocation - penetratorCenter, glm::vec3(0.0f, -1.0f, 0.0f),
|
||||
penetratorRadius, penetration);
|
||||
}
|
||||
|
||||
bool findSphereSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration) {
|
||||
return findSpherePointPenetration(penetratorCenter, penetratorRadius + penetrateeRadius, penetrateeCenter, penetration);
|
||||
}
|
||||
|
||||
bool findSphereSegmentPenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec3& penetrateeStart, const glm::vec3& penetrateeEnd, glm::vec3& penetration) {
|
||||
return findSpherePenetration(computeVectorFromPointToSegment(penetratorCenter, penetrateeStart, penetrateeEnd),
|
||||
glm::vec3(0.0f, -1.0f, 0.0f), penetratorRadius, penetration);
|
||||
}
|
||||
|
||||
bool findSphereCapsulePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, const glm::vec3& penetrateeStart,
|
||||
const glm::vec3& penetrateeEnd, float penetrateeRadius, glm::vec3& penetration) {
|
||||
return findSphereSegmentPenetration(penetratorCenter, penetratorRadius + penetrateeRadius,
|
||||
penetrateeStart, penetrateeEnd, penetration);
|
||||
}
|
||||
|
||||
bool findSpherePlanePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec4& penetrateePlane, glm::vec3& penetration) {
|
||||
float distance = glm::dot(penetrateePlane, glm::vec4(penetratorCenter, 1.0f)) - penetratorRadius;
|
||||
if (distance < 0.0f) {
|
||||
penetration = glm::vec3(penetrateePlane) * distance;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findCapsuleSpherePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius,
|
||||
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration) {
|
||||
if (findSphereCapsulePenetration(penetrateeCenter, penetrateeRadius,
|
||||
penetratorStart, penetratorEnd, penetratorRadius, penetration)) {
|
||||
penetration = -penetration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius,
|
||||
const glm::vec4& penetrateePlane, glm::vec3& penetration) {
|
||||
float distance = glm::min(glm::dot(penetrateePlane, glm::vec4(penetratorStart, 1.0f)),
|
||||
glm::dot(penetrateePlane, glm::vec4(penetratorEnd, 1.0f))) - penetratorRadius;
|
||||
if (distance < 0.0f) {
|
||||
penetration = glm::vec3(penetrateePlane) * distance;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration) {
|
||||
// find the component of the new penetration in the direction of the current
|
||||
float currentLength = glm::length(currentPenetration);
|
||||
if (currentLength == 0.0f) {
|
||||
return newPenetration;
|
||||
}
|
||||
glm::vec3 currentDirection = currentPenetration / currentLength;
|
||||
float directionalComponent = glm::dot(newPenetration, currentDirection);
|
||||
|
||||
// if orthogonal or in the opposite direction, we can simply add
|
||||
if (directionalComponent <= 0.0f) {
|
||||
return currentPenetration + newPenetration;
|
||||
}
|
||||
|
||||
// otherwise, we need to take the maximum component of current and new
|
||||
return currentDirection * glm::max(directionalComponent, currentLength) +
|
||||
newPenetration - (currentDirection * directionalComponent);
|
||||
}
|
||||
|
|
|
@ -13,4 +13,30 @@
|
|||
|
||||
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end);
|
||||
|
||||
bool findSpherePenetration(const glm::vec3& penetratorToPenetratee, const glm::vec3& direction,
|
||||
float combinedRadius, glm::vec3& penetration);
|
||||
|
||||
bool findSpherePointPenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec3& penetrateeLocation, glm::vec3& penetration);
|
||||
|
||||
bool findSphereSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration);
|
||||
|
||||
bool findSphereSegmentPenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec3& penetrateeStart, const glm::vec3& penetrateeEnd, glm::vec3& penetration);
|
||||
|
||||
bool findSphereCapsulePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, const glm::vec3& penetrateeStart,
|
||||
const glm::vec3& penetrateeEnd, float penetrateeRadius, glm::vec3& penetration);
|
||||
|
||||
bool findSpherePlanePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
const glm::vec4& penetrateePlane, glm::vec3& penetration);
|
||||
|
||||
bool findCapsuleSpherePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius,
|
||||
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration);
|
||||
|
||||
bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius,
|
||||
const glm::vec4& penetrateePlane, glm::vec3& penetration);
|
||||
|
||||
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration);
|
||||
|
||||
#endif /* defined(__interface__GeometryUtil__) */
|
||||
|
|
|
@ -716,20 +716,20 @@ public:
|
|||
bool findSpherePenetrationOp(VoxelNode* node, void* extraData) {
|
||||
SphereArgs* args = static_cast<SphereArgs*>(extraData);
|
||||
|
||||
// currently, we treat each node as a sphere enveloping the box
|
||||
const glm::vec3& nodeCenter = node->getCenter();
|
||||
glm::vec3 vector = args->center - nodeCenter;
|
||||
float vectorLength = glm::length(vector);
|
||||
float distance = vectorLength - node->getEnclosingRadius() - args->radius;
|
||||
if (distance >= 0.0f) {
|
||||
// coarse check against bounds
|
||||
const AABox& box = node->getAABox();
|
||||
if (!box.expandedContains(args->center, args->radius)) {
|
||||
return false;
|
||||
}
|
||||
if (!node->isLeaf()) {
|
||||
return true; // recurse on children
|
||||
}
|
||||
if (node->isColored()) {
|
||||
args->penetration += vector * (-distance * TREE_SCALE / vectorLength);
|
||||
args->found = true;
|
||||
glm::vec3 nodePenetration;
|
||||
if (box.findSpherePenetration(args->center, args->radius, nodePenetration)) {
|
||||
args->penetration = addPenetrations(args->penetration, nodePenetration * (float)TREE_SCALE);
|
||||
args->found = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -753,20 +753,20 @@ public:
|
|||
bool findCapsulePenetrationOp(VoxelNode* node, void* extraData) {
|
||||
CapsuleArgs* args = static_cast<CapsuleArgs*>(extraData);
|
||||
|
||||
// currently, we treat each node as a sphere enveloping the box
|
||||
const glm::vec3& nodeCenter = node->getCenter();
|
||||
glm::vec3 vector = computeVectorFromPointToSegment(nodeCenter, args->start, args->end);
|
||||
float vectorLength = glm::length(vector);
|
||||
float distance = vectorLength - node->getEnclosingRadius() - args->radius;
|
||||
if (distance >= 0.0f) {
|
||||
// coarse check against bounds
|
||||
const AABox& box = node->getAABox();
|
||||
if (!box.expandedIntersectsSegment(args->start, args->end, args->radius)) {
|
||||
return false;
|
||||
}
|
||||
if (!node->isLeaf()) {
|
||||
return true; // recurse on children
|
||||
}
|
||||
if (node->isColored()) {
|
||||
args->penetration += vector * (-distance * TREE_SCALE / vectorLength);
|
||||
args->found = true;
|
||||
glm::vec3 nodePenetration;
|
||||
if (box.findCapsulePenetration(args->start, args->end, args->radius, nodePenetration)) {
|
||||
args->penetration = addPenetrations(args->penetration, nodePenetration * (float)TREE_SCALE);
|
||||
args->found = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue