This commit is contained in:
Philip Rosedale 2013-06-03 17:37:25 -07:00
commit 179e30fdfc
13 changed files with 687 additions and 665 deletions

View file

@ -1,48 +1,106 @@
#version 120 #version 120
// //
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
// //
// NVIDIA Statement on the Software // NVIDIA Statement on the Software
// //
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are // The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
// detailed. // detailed.
// //
// No Warranty // No Warranty
// //
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL // 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, // WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// //
// Limitation of Liability // Limitation of Liability
// //
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR // 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 // 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 // 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 // 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 // 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. // 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 // Atmospheric scattering fragment shader
// //
// Author: Sean O'Neil // Author: Sean O'Neil
// //
// Copyright (c) 2004 Sean O'Neil // Copyright (c) 2004 Sean O'Neil
// //
uniform vec3 v3LightPos; uniform vec3 v3CameraPos; // The camera's current position
uniform float g; uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
uniform float g2; uniform float fInnerRadius; // The inner (planetary) radius
uniform float fKrESun; // Kr * ESun
varying vec3 v3Direction; uniform float fKmESun; // Km * ESun
uniform float fKr4PI; // Kr * 4 * PI
uniform float fKm4PI; // Km * 4 * PI
void main (void) 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)
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction); uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
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; const int nSamples = 2;
gl_FragColor.a = gl_FragColor.b; const float fSamples = 2.0;
}
uniform vec3 v3LightPos;
uniform float g;
uniform float g2;
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.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
gl_FragColor.a = gl_FragColor.b;
}

View file

@ -1,100 +1,65 @@
#version 120 #version 120
// //
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
// //
// NVIDIA Statement on the Software // NVIDIA Statement on the Software
// //
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are // The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
// detailed. // detailed.
// //
// No Warranty // No Warranty
// //
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL // 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, // WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// //
// Limitation of Liability // Limitation of Liability
// //
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR // 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 // 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 // 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 // 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 // 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. // 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 // Atmospheric scattering vertex shader
// //
// Author: Sean O'Neil // Author: Sean O'Neil
// //
// Copyright (c) 2004 Sean O'Neil // Copyright (c) 2004 Sean O'Neil
// //
uniform vec3 v3CameraPos; // The camera's current position uniform vec3 v3CameraPos; // The camera's current position
uniform vec3 v3LightPos; // The direction vector to the light source 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 vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
uniform float fInnerRadius; // The inner (planetary) radius uniform float fInnerRadius; // The inner (planetary) radius
uniform float fKrESun; // Kr * ESun uniform float fKrESun; // Kr * ESun
uniform float fKmESun; // Km * ESun uniform float fKmESun; // Km * ESun
uniform float fKr4PI; // Kr * 4 * PI uniform float fKr4PI; // Kr * 4 * PI
uniform float fKm4PI; // Km * 4 * PI uniform float fKm4PI; // Km * 4 * PI
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) 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 fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
const int nSamples = 2; const int nSamples = 2;
const float fSamples = 2.0; const float fSamples = 2.0;
varying vec3 v3Direction; varying vec3 position;
float scale(float fCos) float scale(float fCos)
{ {
float x = 1.0 - fCos; float x = 1.0 - fCos;
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
} }
void main(void) 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) // 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; position = gl_Vertex.xyz;
vec3 v3Ray = v3Pos - v3CameraPos;
float fFar = length(v3Ray); gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
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;
}

View file

@ -1,48 +1,113 @@
#version 120 #version 120
// //
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
// //
// NVIDIA Statement on the Software // NVIDIA Statement on the Software
// //
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are // The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
// detailed. // detailed.
// //
// No Warranty // No Warranty
// //
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL // 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, // WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// //
// Limitation of Liability // Limitation of Liability
// //
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR // 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 // 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 // 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 // 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 // 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. // 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 // Atmospheric scattering fragment shader
// //
// Author: Sean O'Neil // Author: Sean O'Neil
// //
// Copyright (c) 2004 Sean O'Neil // Copyright (c) 2004 Sean O'Neil
// //
uniform vec3 v3LightPos; uniform vec3 v3CameraPos; // The camera's current position
uniform float g; uniform vec3 v3LightPos; // The direction vector to the light source
uniform float g2; uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
uniform float fCameraHeight2; // fCameraHeight^2
varying vec3 v3Direction; uniform float fOuterRadius; // The outer (atmosphere) radius
uniform float fOuterRadius2; // fOuterRadius^2
uniform float fInnerRadius; // The inner (planetary) radius
void main (void) uniform float fKrESun; // Kr * ESun
{ uniform float fKmESun; // Km * ESun
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction); uniform float fKr4PI; // Kr * 4 * PI
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5); uniform float fKm4PI; // Km * 4 * PI
gl_FragColor = gl_Color + fMiePhase * gl_SecondaryColor; uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
gl_FragColor.a = gl_FragColor.b; 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;
}

View file

@ -1,109 +1,41 @@
#version 120 #version 120
// //
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: // For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
// //
// NVIDIA Statement on the Software // NVIDIA Statement on the Software
// //
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are // The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
// detailed. // detailed.
// //
// No Warranty // No Warranty
// //
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL // 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, // WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// //
// Limitation of Liability // Limitation of Liability
// //
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR // 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 // 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 // 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 // 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 // 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. // 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 // Atmospheric scattering vertex shader
// //
// Author: Sean O'Neil // Author: Sean O'Neil
// //
// Copyright (c) 2004 Sean O'Neil // Copyright (c) 2004 Sean O'Neil
// //
uniform vec3 v3CameraPos; // The camera's current position varying vec3 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 void main(void)
uniform float fCameraHeight2; // fCameraHeight^2 {
uniform float fOuterRadius; // The outer (atmosphere) radius position = gl_Vertex.xyz;
uniform float fOuterRadius2; // fOuterRadius^2 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
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;
}

View file

@ -1100,7 +1100,7 @@ void Application::idle() {
} }
} }
} }
// Update audio stats for procedural sounds // Update audio stats for procedural sounds
#ifndef _WIN32 #ifndef _WIN32
_audio.setLastAcceleration(_myAvatar.getThrust()); _audio.setLastAcceleration(_myAvatar.getThrust());

View file

@ -116,7 +116,7 @@ int audioCallback (const void* inputBuffer,
printLog("got output\n"); printLog("got output\n");
} }
if (inputLeft) { if (agentList && inputLeft) {
// Measure the loudness of the signal from the microphone and store in audio object // Measure the loudness of the signal from the microphone and store in audio object
float loudness = 0; float loudness = 0;

View file

@ -33,11 +33,9 @@ const float YOUR_HAND_HOLDING_PULL = 1.0;
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f; const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f;
const float BODY_SPRING_FORCE = 300.0f; const float BODY_SPRING_FORCE = 300.0f;
const float BODY_SPRING_DECAY = 16.0f; const float BODY_SPRING_DECAY = 16.0f;
const float COLLISION_RADIUS_SCALAR = 1.8; const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions
const float COLLISION_BALL_FORCE = 1.0; const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions
const float COLLISION_BODY_FORCE = 6.0; const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions
const float COLLISION_BALL_FRICTION = 60.0;
const float COLLISION_BODY_FRICTION = 0.5;
const float HEAD_ROTATION_SCALE = 0.70; const float HEAD_ROTATION_SCALE = 0.70;
const float HEAD_ROLL_SCALE = 0.40; const float HEAD_ROLL_SCALE = 0.40;
const float HEAD_MAX_PITCH = 45; const float HEAD_MAX_PITCH = 45;
@ -46,7 +44,7 @@ const float HEAD_MAX_YAW = 85;
const float HEAD_MIN_YAW = -85; const float HEAD_MIN_YAW = -85;
const float PERIPERSONAL_RADIUS = 1.0f; const float PERIPERSONAL_RADIUS = 1.0f;
const float AVATAR_BRAKING_STRENGTH = 40.0f; const float AVATAR_BRAKING_STRENGTH = 40.0f;
const float JOINT_TOUCH_RANGE = 0.0005f; const float JOINT_TOUCH_RANGE = 0.01f;
const float FLOATING_HEIGHT = 0.13f; const float FLOATING_HEIGHT = 0.13f;
const bool USING_HEAD_LEAN = false; const bool USING_HEAD_LEAN = false;
const float LEAN_SENSITIVITY = 0.15; const float LEAN_SENSITIVITY = 0.15;
@ -99,8 +97,15 @@ Avatar::Avatar(Agent* owningAgent) :
_driveKeys[i] = false; _driveKeys[i] = false;
} }
initializeSkeleton(); _skeleton.initialize();
initializeBodyBalls();
_height = _skeleton.getHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius + _bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius;
_maxArmLength = _skeleton.getArmLength();
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius;
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius;
_avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS); _avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS);
if (BALLS_ON) { if (BALLS_ON) {
@ -110,6 +115,56 @@ Avatar::Avatar(Agent* owningAgent) :
} }
} }
void Avatar::initializeBodyBalls() {
for (int b=0; b<NUM_AVATAR_JOINTS; b++) {
_bodyBall[b].isCollidable = true;
_bodyBall[b].position = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[b].velocity = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[b].radius = 0.0;
_bodyBall[b].touchForce = 0.0;
_bodyBall[b].jointTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
}
// specify the radii of the joints
_bodyBall[ AVATAR_JOINT_PELVIS ].radius = 0.07;
_bodyBall[ AVATAR_JOINT_TORSO ].radius = 0.065;
_bodyBall[ AVATAR_JOINT_CHEST ].radius = 0.08;
_bodyBall[ AVATAR_JOINT_NECK_BASE ].radius = 0.03;
_bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius = 0.07;
_bodyBall[ AVATAR_JOINT_LEFT_COLLAR ].radius = 0.04;
_bodyBall[ AVATAR_JOINT_LEFT_SHOULDER ].radius = 0.03;
_bodyBall[ AVATAR_JOINT_LEFT_ELBOW ].radius = 0.02;
_bodyBall[ AVATAR_JOINT_LEFT_WRIST ].radius = 0.02;
_bodyBall[ AVATAR_JOINT_LEFT_FINGERTIPS ].radius = 0.01;
_bodyBall[ AVATAR_JOINT_RIGHT_COLLAR ].radius = 0.04;
_bodyBall[ AVATAR_JOINT_RIGHT_SHOULDER ].radius = 0.03;
_bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].radius = 0.02;
_bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].radius = 0.02;
_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].radius = 0.01;
_bodyBall[ AVATAR_JOINT_LEFT_HIP ].radius = 0.04;
_bodyBall[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.025;
_bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.025;
_bodyBall[ AVATAR_JOINT_LEFT_TOES ].radius = 0.025;
_bodyBall[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.04;
_bodyBall[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.025;
_bodyBall[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025;
_bodyBall[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.025;
/*
// to aid in hand-shaking and hand-holding, the right hand is not collidable
_bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].isCollidable = false;
_bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].isCollidable = false;
_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS].isCollidable = false;
*/
}
Avatar::~Avatar() { Avatar::~Avatar() {
_headData = NULL; _headData = NULL;
delete _balls; delete _balls;
@ -216,12 +271,15 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// update balls // update balls
if (_balls) { _balls->simulate(deltaTime); } if (_balls) { _balls->simulate(deltaTime); }
// update avatar skeleton
_skeleton.update(deltaTime, getOrientation(), _position);
// if other avatar, update head position from network data // if this is not my avatar, then hand position comes from transmitted data
if (_owningAgent) {
// update avatar skeleton _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handPosition;
updateSkeleton(); }
//detect and respond to collisions with other avatars... //detect and respond to collisions with other avatars...
if (!_owningAgent) { if (!_owningAgent) {
updateAvatarCollisions(deltaTime); updateAvatarCollisions(deltaTime);
@ -238,8 +296,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
updateCollisionWithEnvironment(); updateCollisionWithEnvironment();
} }
// update body springs // update body balls
updateBodySprings(deltaTime); updateBodyBalls(deltaTime);
// test for avatar collision response with the big sphere // test for avatar collision response with the big sphere
if (usingBigSphereCollisionTest) { if (usingBigSphereCollisionTest) {
@ -391,29 +449,29 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
} }
} }
//apply the head lean values to the springy position... //apply the head lean values to the ball positions...
if (USING_HEAD_LEAN) { if (USING_HEAD_LEAN) {
if (fabs(_head.getLeanSideways() + _head.getLeanForward()) > 0.0f) { if (fabs(_head.getLeanSideways() + _head.getLeanForward()) > 0.0f) {
glm::vec3 headLean = glm::vec3 headLean =
right * _head.getLeanSideways() + right * _head.getLeanSideways() +
front * _head.getLeanForward(); front * _head.getLeanForward();
_joint[ AVATAR_JOINT_TORSO ].springyPosition += headLean * 0.1f; _bodyBall[ AVATAR_JOINT_TORSO ].position += headLean * 0.1f;
_joint[ AVATAR_JOINT_CHEST ].springyPosition += headLean * 0.4f; _bodyBall[ AVATAR_JOINT_CHEST ].position += headLean * 0.4f;
_joint[ AVATAR_JOINT_NECK_BASE ].springyPosition += headLean * 0.7f; _bodyBall[ AVATAR_JOINT_NECK_BASE ].position += headLean * 0.7f;
_joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition += headLean * 1.0f; _bodyBall[ AVATAR_JOINT_HEAD_BASE ].position += headLean * 1.0f;
_joint[ AVATAR_JOINT_LEFT_COLLAR ].springyPosition += headLean * 0.6f; _bodyBall[ AVATAR_JOINT_LEFT_COLLAR ].position += headLean * 0.6f;
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].springyPosition += headLean * 0.6f; _bodyBall[ AVATAR_JOINT_LEFT_SHOULDER ].position += headLean * 0.6f;
_joint[ AVATAR_JOINT_LEFT_ELBOW ].springyPosition += headLean * 0.2f; _bodyBall[ AVATAR_JOINT_LEFT_ELBOW ].position += headLean * 0.2f;
_joint[ AVATAR_JOINT_LEFT_WRIST ].springyPosition += headLean * 0.1f; _bodyBall[ AVATAR_JOINT_LEFT_WRIST ].position += headLean * 0.1f;
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].springyPosition += headLean * 0.0f; _bodyBall[ AVATAR_JOINT_LEFT_FINGERTIPS ].position += headLean * 0.0f;
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].springyPosition += headLean * 0.6f; _bodyBall[ AVATAR_JOINT_RIGHT_COLLAR ].position += headLean * 0.6f;
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].springyPosition += headLean * 0.6f; _bodyBall[ AVATAR_JOINT_RIGHT_SHOULDER ].position += headLean * 0.6f;
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].springyPosition += headLean * 0.2f; _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].position += headLean * 0.2f;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].springyPosition += headLean * 0.1f; _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].position += headLean * 0.1f;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition += headLean * 0.0f; _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += headLean * 0.0f;
} }
} }
@ -426,9 +484,9 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
} }
} }
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
_head.setPosition(_joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition); _head.setPosition(_bodyBall[ AVATAR_JOINT_HEAD_BASE ].position);
_head.setScale (_joint[ AVATAR_JOINT_HEAD_BASE ].radius); _head.setScale (_bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius);
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
_head.simulate(deltaTime, !_owningAgent); _head.simulate(deltaTime, !_owningAgent);
@ -444,13 +502,15 @@ void Avatar::checkForMouseRayTouching() {
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
glm::vec3 directionToBodySphere = glm::normalize(_joint[b].springyPosition - _mouseRayOrigin); glm::vec3 directionToBodySphere = glm::normalize(_bodyBall[b].position - _mouseRayOrigin);
float dot = glm::dot(directionToBodySphere, _mouseRayDirection); float dot = glm::dot(directionToBodySphere, _mouseRayDirection);
if (dot > (1.0f - JOINT_TOUCH_RANGE)) { float range = _bodyBall[b].radius * JOINT_TOUCH_RANGE;
_joint[b].touchForce = (dot - (1.0f - JOINT_TOUCH_RANGE)) / JOINT_TOUCH_RANGE;
if (dot > (1.0f - range)) {
_bodyBall[b].touchForce = (dot - (1.0f - range)) / range;
} else { } else {
_joint[b].touchForce = 0.0; _bodyBall[b].touchForce = 0.0;
} }
} }
} }
@ -473,15 +533,15 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
// reset hand and arm positions according to hand movement // reset hand and arm positions according to hand movement
glm::vec3 right = orientation * AVATAR_RIGHT; glm::vec3 right = orientation * AVATAR_RIGHT;
glm::vec3 up = orientation * AVATAR_UP; glm::vec3 up = orientation * AVATAR_UP;
glm::vec3 front = orientation * AVATAR_FRONT; glm::vec3 front = orientation * AVATAR_FRONT;
glm::vec3 transformedHandMovement glm::vec3 transformedHandMovement
= right * _movedHandOffset.x * 2.0f = right * _movedHandOffset.x * 2.0f
+ up * -_movedHandOffset.y * 2.0f + up * -_movedHandOffset.y * 2.0f
+ front * -_movedHandOffset.z * 2.0f; + front * -_movedHandOffset.y * 2.0f;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement; _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement;
if (!_owningAgent) { if (!_owningAgent) {
_avatarTouch.setMyBodyPosition(_position); _avatarTouch.setMyBodyPosition(_position);
@ -519,8 +579,8 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
_avatarTouch.setHasInteractingOther(true); _avatarTouch.setHasInteractingOther(true);
_avatarTouch.setYourBodyPosition(_interactingOther->_position); _avatarTouch.setYourBodyPosition(_interactingOther->_position);
_avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
_avatarTouch.setYourOrientation (_interactingOther->getOrientation()); _avatarTouch.setYourOrientation (_interactingOther->getOrientation());
_avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
_avatarTouch.setYourHandState (_interactingOther->_handState); _avatarTouch.setYourHandState (_interactingOther->_handState);
//if hand-holding is initiated by either avatar, turn on hand-holding... //if hand-holding is initiated by either avatar, turn on hand-holding...
@ -535,8 +595,8 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
glm::vec3 vectorFromMyHandToYourHand glm::vec3 vectorFromMyHandToYourHand
( (
_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position -
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
); );
float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand); float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand);
@ -558,10 +618,10 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
//if holding hands, apply the appropriate forces //if holding hands, apply the appropriate forces
if (_avatarTouch.getHoldingHands()) { if (_avatarTouch.getHoldingHands()) {
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position +=
( (
_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position _interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
- _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
) * 0.5f; ) * 0.5f;
if (distanceBetweenOurHands > 0.3) { if (distanceBetweenOurHands > 0.3) {
@ -581,7 +641,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
//Set right hand position and state to be transmitted, and also tell AvatarTouch about it //Set right hand position and state to be transmitted, and also tell AvatarTouch about it
if (!_owningAgent) { if (!_owningAgent) {
setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); setHandPosition(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
if (_mousePressed) { if (_mousePressed) {
_handState = HAND_STATE_GRASPING; _handState = HAND_STATE_GRASPING;
@ -590,7 +650,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
} }
_avatarTouch.setMyHandState(_handState); _avatarTouch.setMyHandState(_handState);
_avatarTouch.setMyHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition); _avatarTouch.setMyHandPosition(_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
} }
} }
@ -602,9 +662,9 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d
float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere);
if (distanceToBigSphere < myBodyApproximateBoundingRadius + radius) { if (distanceToBigSphere < myBodyApproximateBoundingRadius + radius) {
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
glm::vec3 vectorFromJointToBigSphereCenter(_joint[b].springyPosition - position); glm::vec3 vectorFromJointToBigSphereCenter(_bodyBall[b].position - position);
float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter);
float combinedRadius = _joint[b].radius + radius; float combinedRadius = _bodyBall[b].radius + radius;
if (distanceToBigSphereCenter < combinedRadius) { if (distanceToBigSphereCenter < combinedRadius) {
jointCollision = true; jointCollision = true;
@ -614,9 +674,9 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d
float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius);
glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration;
_joint[b].springyVelocity += collisionForce * 0.0f * deltaTime; _bodyBall[b].velocity += collisionForce * 0.0f * deltaTime;
_velocity += collisionForce * 40.0f * deltaTime; _velocity += collisionForce * 40.0f * deltaTime;
_joint[b].springyPosition = position + directionVector * combinedRadius; _bodyBall[b].position = position + directionVector * combinedRadius;
} }
} }
} }
@ -674,16 +734,17 @@ void Avatar::updateAvatarCollisions(float deltaTime) {
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
// check if the bounding spheres of the two avatars are colliding // check if the bounding spheres of the two avatars are colliding
glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position);
if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) { if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) {
//apply forces from collision //apply forces from collision
applyCollisionWithOtherAvatar(otherAvatar, deltaTime); applyCollisionWithOtherAvatar(otherAvatar, deltaTime);
} }
// test other avatar hand position for proximity // test other avatar hand position for proximity
glm::vec3 v(_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position); glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
v -= otherAvatar->getPosition(); v -= otherAvatar->getPosition();
float distance = glm::length(v); float distance = glm::length(v);
@ -696,43 +757,34 @@ void Avatar::updateAvatarCollisions(float deltaTime) {
//detect collisions with other avatars and respond //detect collisions with other avatars and respond
void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) { void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) {
float bodyMomentum = 1.0f;
glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f);
// loop through the joints of each avatar to check for every possible collision // loop through the joints of each avatar to check for every possible collision
for (int b=1; b<NUM_AVATAR_JOINTS; b++) { for (int b=1; b<NUM_AVATAR_JOINTS; b++) {
if (_joint[b].isCollidable) { if (_bodyBall[b].isCollidable) {
for (int o=b+1; o<NUM_AVATAR_JOINTS; o++) { for (int o=b+1; o<NUM_AVATAR_JOINTS; o++) {
if (otherAvatar->_joint[o].isCollidable) { if (otherAvatar->_bodyBall[o].isCollidable) {
glm::vec3 vectorBetweenJoints(_joint[b].springyPosition - otherAvatar->_joint[o].springyPosition); glm::vec3 vectorBetweenJoints(_bodyBall[b].position - otherAvatar->_bodyBall[o].position);
float distanceBetweenJoints = glm::length(vectorBetweenJoints); float distanceBetweenJoints = glm::length(vectorBetweenJoints);
if (distanceBetweenJoints > 0.0) { // to avoid divide by zero if (distanceBetweenJoints > 0.0) { // to avoid divide by zero
float combinedRadius = _joint[b].radius + otherAvatar->_joint[o].radius; float combinedRadius = _bodyBall[b].radius + otherAvatar->_bodyBall[o].radius;
// check for collision // check for collision
if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) {
glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints;
// push balls away from each other and apply friction // push balls away from each other and apply friction
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime; float penetration = 1.0f - (distanceBetweenJoints / (combinedRadius * COLLISION_RADIUS_SCALAR));
float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime;
if (ballMomentum < 0.0) { ballMomentum = 0.0;}
_joint[b].springyVelocity += ballPushForce;
otherAvatar->_joint[o].springyVelocity -= ballPushForce;
_joint[b].springyVelocity *= ballMomentum; glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * penetration * deltaTime;
otherAvatar->_joint[o].springyVelocity *= ballMomentum; bodyPushForce += directionVector * COLLISION_BODY_FORCE * penetration * deltaTime;
// accumulate forces and frictions to apply to the velocities of avatar bodies _bodyBall[b].velocity += ballPushForce;
bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime; otherAvatar->_bodyBall[o].velocity -= ballPushForce;
bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime;
if (bodyMomentum < 0.0) { bodyMomentum = 0.0;}
}// check for collision }// check for collision
} // to avoid divide by zero } // to avoid divide by zero
@ -741,12 +793,8 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime
} // b loop } // b loop
} // collidable } // collidable
//apply force on the whole body
//apply forces and frictions on the bodies of both avatars _velocity += bodyPushForce;
_velocity += bodyPushForce;
otherAvatar->_velocity -= bodyPushForce;
_velocity *= bodyMomentum;
otherAvatar->_velocity *= bodyMomentum;
} }
@ -809,11 +857,12 @@ void Avatar::render(bool lookingInMirror) {
} }
glPushMatrix(); glPushMatrix();
glm::vec3 chatPosition = _joint[AVATAR_JOINT_HEAD_BASE].springyPosition + getBodyUpDirection() * chatMessageHeight; glm::vec3 chatPosition = _bodyBall[AVATAR_JOINT_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight;
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 chatAxis = glm::axis(chatRotation); glm::vec3 chatAxis = glm::axis(chatRotation);
glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z); glRotatef(glm::angle(chatRotation), chatAxis.x, chatAxis.y, chatAxis.z);
glColor3f(0, 0.8, 0); glColor3f(0, 0.8, 0);
glRotatef(180, 0, 1, 0); glRotatef(180, 0, 1, 0);
@ -843,252 +892,71 @@ void Avatar::render(bool lookingInMirror) {
} }
} }
void Avatar::initializeSkeleton() { void Avatar::resetBodyBalls() {
for (int b=0; b<NUM_AVATAR_JOINTS; b++) {
_joint[b].isCollidable = true;
_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].springyPosition = glm::vec3(0.0, 0.0, 0.0);
_joint[b].springyVelocity = glm::vec3(0.0, 0.0, 0.0);
_joint[b].orientation = glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
_joint[b].length = 0.0;
_joint[b].radius = 0.0;
_joint[b].touchForce = 0.0;
_joint[b].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
}
// 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 );
// specify the radii of the joints
_joint[ AVATAR_JOINT_PELVIS ].radius = 0.07;
_joint[ AVATAR_JOINT_TORSO ].radius = 0.065;
_joint[ AVATAR_JOINT_CHEST ].radius = 0.08;
_joint[ AVATAR_JOINT_NECK_BASE ].radius = 0.03;
_joint[ AVATAR_JOINT_HEAD_BASE ].radius = 0.07;
_joint[ AVATAR_JOINT_LEFT_COLLAR ].radius = 0.04;
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].radius = 0.03;
_joint[ AVATAR_JOINT_LEFT_ELBOW ].radius = 0.02;
_joint[ AVATAR_JOINT_LEFT_WRIST ].radius = 0.02;
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].radius = 0.01;
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].radius = 0.04;
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].radius = 0.03;
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].radius = 0.02;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].radius = 0.02;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].radius = 0.01;
_joint[ AVATAR_JOINT_LEFT_HIP ].radius = 0.04;
_joint[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.025;
_joint[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.025;
_joint[ AVATAR_JOINT_LEFT_TOES ].radius = 0.025;
_joint[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.04;
_joint[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.025;
_joint[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025;
_joint[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.025;
// to aid in hand-shaking and hand-holding, the right hand is not collidable
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].isCollidable = false;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].isCollidable = false;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].isCollidable = false;
// calculate bone length
calculateBoneLengths();
_pelvisStandingHeight =
_joint[ AVATAR_JOINT_LEFT_HEEL ].radius +
_joint[ AVATAR_JOINT_LEFT_HEEL ].length +
_joint[ AVATAR_JOINT_LEFT_KNEE ].length;
//printf("_pelvisStandingHeight = %f\n", _pelvisStandingHeight);
_pelvisFloatingHeight = _pelvisStandingHeight + FLOATING_HEIGHT;
_height =
(
_pelvisStandingHeight +
_joint[ AVATAR_JOINT_LEFT_HEEL ].radius +
_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 +
_joint[ AVATAR_JOINT_HEAD_BASE ].radius
);
//printf("_height = %f\n", _height);
// generate joint positions by updating the skeleton
updateSkeleton();
//set spring positions to be in the skeleton bone positions
initializeBodySprings();
}
void Avatar::calculateBoneLengths() {
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
_joint[b].length = glm::length(_joint[b].defaultPosePosition); _bodyBall[b].position = _skeleton.joint[b].position;
} _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
_maxArmLength
= _joint[ AVATAR_JOINT_RIGHT_ELBOW ].length
+ _joint[ AVATAR_JOINT_RIGHT_WRIST ].length
+ _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].length;
}
void Avatar::updateSkeleton() {
// rotate body...
glm::quat orientation = getOrientation();
// calculate positions of all bones by traversing the skeleton tree:
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
if (_joint[b].parent == AVATAR_JOINT_NULL) {
_joint[b].orientation = orientation;
_joint[b].position = _position;
}
else {
_joint[b].orientation = _joint[ _joint[b].parent ].orientation;
_joint[b].position = _joint[ _joint[b].parent ].position;
}
// if this is not my avatar, then hand position comes from transmitted data
if (_owningAgent) {
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handPosition;
}
// the following will be replaced by a proper rotation...close
glm::vec3 rotatedJointVector = _joint[b].orientation * _joint[b].defaultPosePosition;
//glm::vec3 myEuler (0.0f, 0.0f, 0.0f);
//glm::quat myQuat (myEuler);
_joint[b].position += rotatedJointVector;
} }
} }
void Avatar::initializeBodySprings() { void Avatar::updateBodyBalls(float deltaTime) {
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { // Check for a large repositioning, and re-initialize balls if this has happened
_joint[b].springyPosition = _joint[b].position;
_joint[b].springyVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
}
void Avatar::updateBodySprings(float deltaTime) {
// Check for a large repositioning, and re-initialize body springs if this has happened
const float BEYOND_BODY_SPRING_RANGE = 2.f; const float BEYOND_BODY_SPRING_RANGE = 2.f;
if (glm::length(_position - _joint[AVATAR_JOINT_PELVIS].springyPosition) > BEYOND_BODY_SPRING_RANGE) { if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) {
initializeBodySprings(); resetBodyBalls();
} }
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
glm::vec3 springVector(_joint[b].springyPosition); glm::vec3 springVector(_bodyBall[b].position);
if (_joint[b].parent == AVATAR_JOINT_NULL) { if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL) {
springVector -= _position; springVector -= _position;
} }
else { else {
springVector -= _joint[ _joint[b].parent ].springyPosition; springVector -= _bodyBall[ _skeleton.joint[b].parent ].position;
} }
float length = glm::length(springVector); float length = glm::length(springVector);
if (length > 0.0f) { // to avoid divide by zero if (length > 0.0f) { // to avoid divide by zero
glm::vec3 springDirection = springVector / length; glm::vec3 springDirection = springVector / length;
float force = (length - _skeleton.joint[b].length) * BODY_SPRING_FORCE * deltaTime;
_bodyBall[b].velocity -= springDirection * force;
float force = (length - _joint[b].length) * BODY_SPRING_FORCE * deltaTime; if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) {
_bodyBall[_skeleton.joint[b].parent].velocity += springDirection * force;
_joint[b].springyVelocity -= springDirection * force;
if (_joint[b].parent != AVATAR_JOINT_NULL) {
_joint[_joint[b].parent].springyVelocity += springDirection * force;
} }
} }
// apply tightness force - (causing springy position to be close to rigid body position) // apply tightness force - (causing ball position to be close to skeleton joint position)
_joint[b].springyVelocity += (_joint[b].position - _joint[b].springyPosition) * _joint[b].springBodyTightness * deltaTime; _bodyBall[b].velocity += (_skeleton.joint[b].position - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime;
// apply decay // apply decay
float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; float decay = 1.0 - BODY_SPRING_DECAY * deltaTime;
if (decay > 0.0) { if (decay > 0.0) {
_joint[b].springyVelocity *= decay; _bodyBall[b].velocity *= decay;
} }
else { else {
_joint[b].springyVelocity = glm::vec3(0.0f, 0.0f, 0.0f); _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
} }
/* /*
//apply forces from touch... //apply forces from touch...
if (_joint[b].touchForce > 0.0) { if (_skeleton.joint[b].touchForce > 0.0) {
_joint[b].springyVelocity += _mouseRayDirection * _joint[b].touchForce * 0.7f; _skeleton.joint[b].springyVelocity += _mouseRayDirection * _skeleton.joint[b].touchForce * 0.7f;
} }
*/ */
//update position by velocity... //update position by velocity...
_joint[b].springyPosition += _joint[b].springyVelocity * deltaTime; _bodyBall[b].position += _bodyBall[b].velocity * deltaTime;
} }
} }
void Avatar::updateArmIKAndConstraints(float deltaTime) { void Avatar::updateArmIKAndConstraints(float deltaTime) {
// determine the arm vector // determine the arm vector
glm::vec3 armVector = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position; glm::vec3 armVector = _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position;
armVector -= _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; armVector -= _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position;
// test to see if right hand is being dragged beyond maximum arm length // test to see if right hand is being dragged beyond maximum arm length
float distance = glm::length(armVector); float distance = glm::length(armVector);
@ -1096,29 +964,28 @@ void Avatar::updateArmIKAndConstraints(float deltaTime) {
// don't let right hand get dragged beyond maximum arm length... // don't let right hand get dragged beyond maximum arm length...
if (distance > _maxArmLength) { if (distance > _maxArmLength) {
// reset right hand to be constrained to maximum arm length // reset right hand to be constrained to maximum arm length
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position;
glm::vec3 armNormal = armVector / distance; glm::vec3 armNormal = armVector / distance;
armVector = armNormal * _maxArmLength; armVector = armNormal * _maxArmLength;
distance = _maxArmLength; distance = _maxArmLength;
glm::vec3 constrainedPosition = _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; glm::vec3 constrainedPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position;
constrainedPosition += armVector; constrainedPosition += armVector;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = constrainedPosition; _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = constrainedPosition;
} }
// set elbow position // set elbow position
glm::vec3 newElbowPosition = _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; glm::vec3 newElbowPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position + armVector * ONE_HALF;
newElbowPosition += armVector * ONE_HALF;
glm::vec3 perpendicular = glm::cross(getBodyFrontDirection(), armVector); glm::vec3 perpendicular = glm::cross(getBodyRightDirection(), armVector);
newElbowPosition += perpendicular * (1.0f - (_maxArmLength / distance)) * ONE_HALF; newElbowPosition += perpendicular * (1.0f - (_maxArmLength / distance)) * ONE_HALF;
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].position = newElbowPosition; _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position = newElbowPosition;
// set wrist position // set wrist position
glm::vec3 vv(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); glm::vec3 vv(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
vv -= _joint[ AVATAR_JOINT_RIGHT_ELBOW ].position; vv -= _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position;
glm::vec3 newWristPosition = _joint[ AVATAR_JOINT_RIGHT_ELBOW ].position + vv * 0.7f; glm::vec3 newWristPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position + vv * 0.7f;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].position = newWristPosition; _skeleton.joint[ AVATAR_JOINT_RIGHT_WRIST ].position = newWristPosition;
} }
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
@ -1144,7 +1011,7 @@ void Avatar::renderBody(bool lookingInMirror) {
// Render the body as balls and cones // Render the body as balls and cones
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
float distanceToCamera = glm::length(_cameraPosition - _joint[b].position); float distanceToCamera = glm::length(_cameraPosition - _skeleton.joint[b].position);
float alpha = lookingInMirror ? 1.0f : glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / float alpha = lookingInMirror ? 1.0f : glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND) /
(RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f);
@ -1166,26 +1033,26 @@ void Avatar::renderBody(bool lookingInMirror) {
if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW
|| b == AVATAR_JOINT_RIGHT_WRIST || b == AVATAR_JOINT_RIGHT_WRIST
|| b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) {
glColor3f(SKIN_COLOR[0] + _joint[b].touchForce * 0.3f, glColor3f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f,
SKIN_COLOR[1] - _joint[b].touchForce * 0.2f, SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f,
SKIN_COLOR[2] - _joint[b].touchForce * 0.1f); SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f);
} else { } else {
glColor4f(SKIN_COLOR[0] + _joint[b].touchForce * 0.3f, glColor4f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f,
SKIN_COLOR[1] - _joint[b].touchForce * 0.2f, SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f,
SKIN_COLOR[2] - _joint[b].touchForce * 0.1f, SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f,
alpha); alpha);
} }
if ((b != AVATAR_JOINT_HEAD_TOP ) if ((b != AVATAR_JOINT_HEAD_TOP )
&& (b != AVATAR_JOINT_HEAD_BASE )) { && (b != AVATAR_JOINT_HEAD_BASE )) {
glPushMatrix(); glPushMatrix();
glTranslatef(_joint[b].springyPosition.x, _joint[b].springyPosition.y, _joint[b].springyPosition.z); glTranslatef(_bodyBall[b].position.x, _bodyBall[b].position.y, _bodyBall[b].position.z);
glutSolidSphere(_joint[b].radius, 20.0f, 20.0f); glutSolidSphere(_bodyBall[b].radius, 20.0f, 20.0f);
glPopMatrix(); glPopMatrix();
} }
// Render the cone connecting this joint to its parent // Render the cone connecting this joint to its parent
if (_joint[b].parent != AVATAR_JOINT_NULL) { if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) {
if ((b != AVATAR_JOINT_HEAD_TOP ) if ((b != AVATAR_JOINT_HEAD_TOP )
&& (b != AVATAR_JOINT_HEAD_BASE ) && (b != AVATAR_JOINT_HEAD_BASE )
&& (b != AVATAR_JOINT_PELVIS ) && (b != AVATAR_JOINT_PELVIS )
@ -1197,15 +1064,15 @@ void Avatar::renderBody(bool lookingInMirror) {
&& (b != AVATAR_JOINT_RIGHT_SHOULDER)) { && (b != AVATAR_JOINT_RIGHT_SHOULDER)) {
glColor3fv(DARK_SKIN_COLOR); glColor3fv(DARK_SKIN_COLOR);
float r1 = _joint[_joint[b].parent ].radius * 0.8; float r1 = _bodyBall[_skeleton.joint[b].parent ].radius * 0.8;
float r2 = _joint[b ].radius * 0.8; float r2 = _bodyBall[b ].radius * 0.8;
if (b == AVATAR_JOINT_HEAD_BASE) { if (b == AVATAR_JOINT_HEAD_BASE) {
r1 *= 0.5f; r1 *= 0.5f;
} }
renderJointConnectingCone renderJointConnectingCone
( (
_joint[_joint[b].parent ].springyPosition, _bodyBall[_skeleton.joint[b].parent ].position,
_joint[b ].springyPosition, r2, r2 _bodyBall[b ].position, r2, r2
); );
} }
} }

View file

@ -64,24 +64,28 @@ public:
void setOrientation (const glm::quat& orientation); void setOrientation (const glm::quat& orientation);
//getters //getters
float getHeadYawRate () const { return _head.yawRate;}
float getBodyYaw () const { return _bodyYaw;} float getHeadYawRate () const { return _head.yawRate;}
bool getIsNearInteractingOther () const { return _avatarTouch.getAbleToReachOtherAvatar();} float getBodyYaw () const { return _bodyYaw;}
const glm::vec3& getHeadPosition () const { return _joint[ AVATAR_JOINT_HEAD_BASE ].position;} bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();}
const glm::vec3& getSpringyHeadPosition () const { return _joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition;} const glm::vec3& getHeadPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;}
const glm::vec3& getJointPosition (AvatarJointID j) const { return _joint[j].springyPosition;} const glm::vec3& getSpringyHeadPosition () const { return _bodyBall[ AVATAR_JOINT_HEAD_BASE ].position;}
const glm::vec3& getJointPosition (AvatarJointID j) const { return _bodyBall[j].position;}
glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; } glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; }
glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; } glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; }
glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; } 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;} const glm::vec3& getVelocity () const { return _velocity;}
AvatarMode getMode () const { return _mode;} float getSpeed () const { return _speed;}
float getAbsoluteHeadYaw () const; float getHeight () const { return _height;}
float getAbsoluteHeadPitch () const; AvatarMode getMode () const { return _mode;}
Head& getHead () { return _head; } float getAbsoluteHeadYaw () const;
glm::quat getOrientation () const; float getAbsoluteHeadPitch () const;
glm::quat getWorldAlignedOrientation () const; Head& getHead () {return _head; }
glm::quat getOrientation () const;
glm::quat getWorldAlignedOrientation() const;
// Set what driving keys are being pressed to control thrust levels // Set what driving keys are being pressed to control thrust levels
void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; void setDriveKeys(int key, bool val) { _driveKeys[key] = val; };
@ -100,19 +104,14 @@ private:
Avatar(const Avatar&); Avatar(const Avatar&);
Avatar& operator= (const Avatar&); Avatar& operator= (const Avatar&);
struct AvatarJoint struct AvatarBall
{ {
AvatarJointID parent; // which joint is this joint connected to? glm::vec3 position;
glm::vec3 position; // the position at the "end" of the joint - in global space glm::vec3 velocity;
glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" float jointTightness;
glm::vec3 springyPosition; // used for special effects (a 'flexible' variant of position) float radius;
glm::vec3 springyVelocity; // used for special effects ( the velocity of the springy position) bool isCollidable;
float springBodyTightness; // how tightly the springy position tries to stay on the position float touchForce;
glm::quat orientation; // this will eventually replace yaw, pitch and roll (and maybe orientation)
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)
}; };
Head _head; Head _head;
@ -124,7 +123,8 @@ private:
float _bodyYawDelta; float _bodyYawDelta;
float _bodyRollDelta; float _bodyRollDelta;
glm::vec3 _movedHandOffset; glm::vec3 _movedHandOffset;
AvatarJoint _joint[ NUM_AVATAR_JOINTS ]; glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
AvatarBall _bodyBall[ NUM_AVATAR_JOINTS ];
AvatarMode _mode; AvatarMode _mode;
glm::vec3 _cameraPosition; glm::vec3 _cameraPosition;
glm::vec3 _handHoldingPosition; glm::vec3 _handHoldingPosition;
@ -152,10 +152,9 @@ private:
glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat)
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
void renderBody(bool lookingInMirror); void renderBody(bool lookingInMirror);
void initializeSkeleton(); void initializeBodyBalls();
void updateSkeleton(); void resetBodyBalls();
void initializeBodySprings(); void updateBodyBalls( float deltaTime );
void updateBodySprings( float deltaTime );
void calculateBoneLengths(); void calculateBoneLengths();
void readSensors(); void readSensors();
void updateHandMovementAndTouching(float deltaTime); void updateHandMovementAndTouching(float deltaTime);

View file

@ -43,6 +43,10 @@ void AvatarTouch::simulate (float deltaTime) {
glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition; glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition;
float distanceBetweenBodies = glm::length(vectorBetweenBodies); float distanceBetweenBodies = glm::length(vectorBetweenBodies);
//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; glm::vec3 directionBetweenBodies = vectorBetweenBodies / distanceBetweenBodies;
bool facingEachOther = false; bool facingEachOther = false;
@ -50,12 +54,14 @@ void AvatarTouch::simulate (float deltaTime) {
glm::vec3 myFront = _myOrientation * AVATAR_FRONT; glm::vec3 myFront = _myOrientation * AVATAR_FRONT;
glm::vec3 yourFront = _yourOrientation * AVATAR_FRONT; glm::vec3 yourFront = _yourOrientation * AVATAR_FRONT;
if (( glm::dot(myFront, yourFront) < -AVATAR_FACING_THRESHOLD) // we're facing each other if (( glm::dot(myFront, yourFront ) < -AVATAR_FACING_THRESHOLD) // we're facing each other
&& ( glm::dot(myFront, directionBetweenBodies ) > AVATAR_FACING_THRESHOLD)) { // I'm facing you && ( glm::dot(myFront, directionBetweenBodies ) > AVATAR_FACING_THRESHOLD)) { // I'm facing you
facingEachOther = true; facingEachOther = true;
} }
*/
if (distanceBetweenBodies < _reachableRadius) {
if (distanceBetweenBodies < _reachableRadius)
{
_canReachToOtherAvatar = true; _canReachToOtherAvatar = true;
_vectorBetweenHands = _yourHandPosition - _myHandPosition; _vectorBetweenHands = _yourHandPosition - _myHandPosition;

View file

@ -32,7 +32,7 @@ Camera::Camera() {
_needsToInitialize = true; _needsToInitialize = true;
_frustumNeedsReshape = true; _frustumNeedsReshape = true;
_modeShift = 0.0f; _modeShift = 1.0f;
_modeShiftRate = 1.0f; _modeShiftRate = 1.0f;
_linearModeShift = 0.0f; _linearModeShift = 0.0f;
_mode = CAMERA_MODE_THIRD_PERSON; _mode = CAMERA_MODE_THIRD_PERSON;

View file

@ -20,7 +20,6 @@ const float EYE_RIGHT_OFFSET = 0.27f;
const float EYE_UP_OFFSET = 0.36f; const float EYE_UP_OFFSET = 0.36f;
const float EYE_FRONT_OFFSET = 0.8f; const float EYE_FRONT_OFFSET = 0.8f;
const float EAR_RIGHT_OFFSET = 1.0; const float EAR_RIGHT_OFFSET = 1.0;
//const float MOUTH_FRONT_OFFSET = 0.9f;
const float MOUTH_UP_OFFSET = -0.3f; const float MOUTH_UP_OFFSET = -0.3f;
const float HEAD_MOTION_DECAY = 0.1; 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 MINIMUM_EYE_ROTATION_DOT = 0.5f; // based on a dot product: 1.0 is straight ahead, 0.0 is 90 degrees off
@ -276,7 +275,7 @@ void Head::renderMohawk(glm::vec3 cameraPosition) {
glm::vec3 mid2 = _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); glColor3f(_mohawkColors[t].x, _mohawkColors[t].y, _mohawkColors[t].z);
glBegin(GL_TRIANGLES); glBegin(GL_TRIANGLES);
glVertex3f(base1.x, base1.y, base1.z ); glVertex3f(base1.x, base1.y, base1.z );
glVertex3f(base2.x, base2.y, base2.z ); glVertex3f(base2.x, base2.y, base2.z );
@ -374,7 +373,7 @@ void Head::renderMouth() {
rightTop = _position + glm::normalize(rightTop - _position) * constrainedRadius; rightTop = _position + glm::normalize(rightTop - _position) * constrainedRadius;
leftBottom = _position + glm::normalize(leftBottom - _position) * constrainedRadius; leftBottom = _position + glm::normalize(leftBottom - _position) * constrainedRadius;
rightBottom = _position + glm::normalize(rightBottom - _position) * constrainedRadius; rightBottom = _position + glm::normalize(rightBottom - _position) * constrainedRadius;
glColor3f(0.2f, 0.0f, 0.0f); glColor3f(0.2f, 0.0f, 0.0f);
glBegin(GL_TRIANGLES); glBegin(GL_TRIANGLES);

View file

@ -6,15 +6,129 @@
#include "Skeleton.h" #include "Skeleton.h"
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f;
const float FLOATING_HEIGHT = 0.13f;
Skeleton::Skeleton() { Skeleton::Skeleton() {
} }
void Skeleton::initialize() { 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);
}
} }
void Skeleton::render() { // 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;
}
} }
void Skeleton::simulate(float deltaTime) { 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;
}

View file

@ -8,6 +8,9 @@
#ifndef hifi_Skeleton_h #ifndef hifi_Skeleton_h
#define hifi_Skeleton_h #define hifi_Skeleton_h
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
enum AvatarJointID enum AvatarJointID
{ {
AVATAR_JOINT_NULL = -1, AVATAR_JOINT_NULL = -1,
@ -45,10 +48,24 @@ public:
Skeleton(); Skeleton();
void initialize(); void initialize();
void simulate(float deltaTime); void update(float deltaTime, const glm::quat&, glm::vec3 position);
void render(); void render();
private: float getArmLength();
}; float getHeight();
float getPelvisStandingHeight();
float getPelvisFloatingHeight();
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 "T-pose"
glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion
float length; // the length of vector connecting the joint and its parent
};
AvatarJoint joint[ NUM_AVATAR_JOINTS ];
};
#endif #endif