mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
option to turn on/off string hair
This commit is contained in:
parent
40dee3b39e
commit
58d460da09
6 changed files with 110 additions and 49 deletions
67
examples/concertCamera.js
Normal file
67
examples/concertCamera.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// concertCamera.js
|
||||
//
|
||||
// Created by Philip Rosedale on June 24, 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Move a camera through a series of pre-set locations by pressing number keys
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var oldMode;
|
||||
var avatarPosition;
|
||||
|
||||
var cameraNumber = 0;
|
||||
var freeCamera = false;
|
||||
|
||||
var cameraLocations = [ {x: 7972.0, y: 241.6, z: 7304.1}, {x: 7973.7, y: 241.6, z: 7304.1}, {x: 7975.5, y: 241.6, z: 7304.1}, {x: 7972.3, y: 241.6, z: 7303.3}, {x: 7971.4, y: 241.6, z: 7304.3} ];
|
||||
var cameraLookAts = [ {x: 7971.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1} ];
|
||||
|
||||
function saveCameraState() {
|
||||
oldMode = Camera.getMode();
|
||||
avatarPosition = MyAvatar.position;
|
||||
Camera.setModeShiftPeriod(0.0);
|
||||
Camera.setMode("independent");
|
||||
}
|
||||
|
||||
function restoreCameraState() {
|
||||
Camera.stopLooking();
|
||||
Camera.setMode(oldMode);
|
||||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
if (freeCamera) {
|
||||
var delta = Vec3.subtract(MyAvatar.position, avatarPosition);
|
||||
if (Vec3.length(delta) > 0.05) {
|
||||
cameraNumber = 0;
|
||||
freeCamera = false;
|
||||
restoreCameraState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
|
||||
var choice = parseInt(event.text);
|
||||
|
||||
if ((choice > 0) && (choice <= cameraLocations.length)) {
|
||||
print("camera " + choice);
|
||||
if (!freeCamera) {
|
||||
saveCameraState();
|
||||
freeCamera = true;
|
||||
}
|
||||
Camera.setMode("independent");
|
||||
Camera.setPosition(cameraLocations[choice - 1]);
|
||||
Camera.keepLookingAt(cameraLookAts[choice - 1]);
|
||||
}
|
||||
if (event.text == "0") {
|
||||
// Show camera location in log
|
||||
var cameraLocation = Camera.getPosition();
|
||||
print(cameraLocation.x + ", " + cameraLocation.y + ", " + cameraLocation.z);
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(update);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
|
@ -345,6 +345,7 @@ Menu::Menu() :
|
|||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::StringHair, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
|
||||
|
||||
|
|
|
@ -319,6 +319,7 @@ namespace MenuOption {
|
|||
const QString Bandwidth = "Bandwidth Display";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BuckyBalls = "Bucky Balls";
|
||||
const QString StringHair = "String Hair";
|
||||
const QString CascadedShadows = "Cascaded";
|
||||
const QString Chat = "Chat...";
|
||||
const QString ChatCircling = "Chat Circling";
|
||||
|
|
|
@ -140,7 +140,9 @@ void Avatar::simulate(float deltaTime) {
|
|||
head->setScale(_scale);
|
||||
head->simulate(deltaTime, false, _shouldRenderBillboard);
|
||||
|
||||
simulateHair(deltaTime);
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
simulateHair(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
// update position by velocity, and subtract the change added earlier for gravity
|
||||
|
@ -376,26 +378,32 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
|
|||
getHand()->render(false, modelRenderMode);
|
||||
}
|
||||
getHead()->render(1.0f, modelRenderMode);
|
||||
renderHair();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
renderHair();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Constants for the Hair Simulation
|
||||
//
|
||||
|
||||
const float HAIR_LENGTH = 0.2f;
|
||||
const float HAIR_LINK_LENGTH = HAIR_LENGTH / HAIR_LINKS;
|
||||
const float HAIR_DAMPING = 0.99f;
|
||||
const float HEAD_RADIUS = 0.18f;
|
||||
const float CONSTRAINT_RELAXATION = 20.0f;
|
||||
const glm::vec3 HAIR_GRAVITY(0.f, -0.015f, 0.f);
|
||||
const float HEAD_RADIUS = 0.21f;
|
||||
const float CONSTRAINT_RELAXATION = 10.0f;
|
||||
const glm::vec3 HAIR_GRAVITY(0.0f, -0.007f, 0.0f);
|
||||
const float HAIR_ACCELERATION_COUPLING = 0.025f;
|
||||
const float HAIR_ANGULAR_VELOCITY_COUPLING = 0.10f;
|
||||
const float HAIR_MAX_LINEAR_ACCELERATION = 4.f;
|
||||
const float HAIR_THICKNESS = 0.020f;
|
||||
const float HAIR_STIFFNESS = 0.0006f;
|
||||
const float HAIR_MAX_LINEAR_ACCELERATION = 4.0f;
|
||||
const float HAIR_THICKNESS = 0.015f;
|
||||
const float HAIR_STIFFNESS = 0.0000f;
|
||||
const glm::vec3 HAIR_COLOR1(0.98f, 0.92f, 0.843f);
|
||||
const glm::vec3 HAIR_COLOR2(0.545f, 0.533f, 0.47f);
|
||||
const glm::vec3 WIND_DIRECTION(0.5f, -1.0f, 0.f);
|
||||
const float MAX_WIND_STRENGTH = 0.01f;
|
||||
const float FINGER_LENGTH = 0.25;
|
||||
const float FINGER_RADIUS = 0.10;
|
||||
const glm::vec3 WIND_DIRECTION(0.5f, -1.0f, 0.0f);
|
||||
const float MAX_WIND_STRENGTH = 0.02f;
|
||||
const float FINGER_LENGTH = 0.25f;
|
||||
const float FINGER_RADIUS = 0.10f;
|
||||
|
||||
void Avatar::renderHair() {
|
||||
//
|
||||
|
@ -403,26 +411,6 @@ void Avatar::renderHair() {
|
|||
//
|
||||
|
||||
glm::vec3 headPosition = getHead()->getPosition();
|
||||
/*
|
||||
glm::vec3 leftHandPosition, rightHandPosition;
|
||||
getSkeletonModel().getLeftHandPosition(leftHandPosition);
|
||||
getSkeletonModel().getRightHandPosition(rightHandPosition);
|
||||
glm::quat leftRotation, rightRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
|
||||
rightHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.f) * glm::inverse(rightRotation);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(leftHandPosition.x, leftHandPosition.y, leftHandPosition.z);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
|
||||
glutSolidSphere(FINGER_RADIUS, 20, 20);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(rightHandPosition.x, rightHandPosition.y, rightHandPosition.z);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
|
||||
glutSolidSphere(FINGER_RADIUS, 20, 20);
|
||||
glPopMatrix();
|
||||
*/
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(headPosition.x, headPosition.y, headPosition.z);
|
||||
const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame();
|
||||
|
@ -458,7 +446,7 @@ void Avatar::renderHair() {
|
|||
|
||||
void Avatar::simulateHair(float deltaTime) {
|
||||
|
||||
deltaTime = glm::clamp(deltaTime, 0.f, 1.f / 30.f);
|
||||
deltaTime = glm::clamp(deltaTime, 0.0f, 1.0f / 30.0f);
|
||||
glm::vec3 acceleration = getAcceleration();
|
||||
if (glm::length(acceleration) > HAIR_MAX_LINEAR_ACCELERATION) {
|
||||
acceleration = glm::normalize(acceleration) * HAIR_MAX_LINEAR_ACCELERATION;
|
||||
|
@ -476,8 +464,8 @@ void Avatar::simulateHair(float deltaTime) {
|
|||
glm::quat leftRotation, rightRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
|
||||
leftHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.f) * glm::inverse(leftRotation);
|
||||
rightHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.f) * glm::inverse(rightRotation);
|
||||
leftHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.0f) * glm::inverse(leftRotation);
|
||||
rightHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.0f) * glm::inverse(rightRotation);
|
||||
leftHandPosition = leftHandPosition * rotation;
|
||||
rightHandPosition = rightHandPosition * rotation;
|
||||
|
||||
|
@ -499,9 +487,9 @@ void Avatar::simulateHair(float deltaTime) {
|
|||
// Resolve collision with head sphere
|
||||
if (glm::length(_hairPosition[vertexIndex]) < HEAD_RADIUS) {
|
||||
_hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex]) *
|
||||
(HEAD_RADIUS - glm::length(_hairPosition[vertexIndex])); // * COLLISION_RELAXATION * deltaTime;
|
||||
(HEAD_RADIUS - glm::length(_hairPosition[vertexIndex]));
|
||||
}
|
||||
// Collide with hands
|
||||
// Resolve collision with hands
|
||||
if (glm::length(_hairPosition[vertexIndex] - leftHandPosition) < FINGER_RADIUS) {
|
||||
_hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex] - leftHandPosition) *
|
||||
(FINGER_RADIUS - glm::length(_hairPosition[vertexIndex] - leftHandPosition));
|
||||
|
@ -518,7 +506,7 @@ void Avatar::simulateHair(float deltaTime) {
|
|||
// Add linear acceleration of the avatar body
|
||||
_hairPosition[vertexIndex] -= acceleration * HAIR_ACCELERATION_COUPLING * deltaTime;
|
||||
|
||||
// Add stiffness (product)
|
||||
// Add stiffness (like hair care products do)
|
||||
_hairPosition[vertexIndex] += (_hairOriginalPosition[vertexIndex] - _hairPosition[vertexIndex])
|
||||
* powf(1.f - link / HAIR_LINKS, 2.f) * HAIR_STIFFNESS;
|
||||
|
||||
|
@ -580,13 +568,8 @@ void Avatar::initializeHair() {
|
|||
float strandAngle = randFloat() * PI;
|
||||
float azimuth = FACE_WIDTH / 2.0f + (randFloat() * (2.0 * PI - FACE_WIDTH));
|
||||
float elevation = PI_OVER_TWO - (randFloat() * 0.75 * PI);
|
||||
/*if ((azimuth > FACE_WIDTH) || (azimuth < -FACE_WIDTH)) {
|
||||
elevation = randFloat() * PI_OVER_TWO;
|
||||
} else {
|
||||
elevation = (PI_OVER_TWO / 2.f) + randFloat() * (PI_OVER_TWO / 2.f);
|
||||
}*/
|
||||
glm::vec3 thisStrand(sinf(azimuth) * cosf(elevation), sinf(elevation), -cosf(azimuth) * cosf(elevation));
|
||||
thisStrand *= HEAD_RADIUS + 0.01f;
|
||||
thisStrand *= HEAD_RADIUS;
|
||||
|
||||
for (int link = 0; link < HAIR_LINKS; link++) {
|
||||
int vertexIndex = strand * HAIR_LINKS + link;
|
||||
|
@ -610,6 +593,7 @@ void Avatar::initializeHair() {
|
|||
_hairOriginalPosition[vertexIndex] = _hairPosition[vertexIndex];
|
||||
|
||||
_hairQuadDelta[vertexIndex] = glm::vec3(cos(strandAngle) * HAIR_THICKNESS, 0.f, sin(strandAngle) * HAIR_THICKNESS);
|
||||
_hairQuadDelta[vertexIndex] *= 1.f - (link / HAIR_LINKS);
|
||||
_hairNormals[vertexIndex] = glm::normalize(randVector());
|
||||
if (randFloat() < elevation / PI_OVER_TWO) {
|
||||
_hairColors[vertexIndex] = HAIR_COLOR1 * ((float)(link + 1) / (float)HAIR_LINKS);
|
||||
|
|
|
@ -32,9 +32,9 @@ static const float RESCALING_TOLERANCE = .02f;
|
|||
extern const float CHAT_MESSAGE_SCALE;
|
||||
extern const float CHAT_MESSAGE_HEIGHT;
|
||||
|
||||
const int HAIR_STRANDS = 200; // Number of strands of hair
|
||||
const int HAIR_LINKS = 10; // Number of links in a hair strand
|
||||
const int HAIR_MAX_CONSTRAINTS = 2;
|
||||
const int HAIR_STRANDS = 150; // Number of strands of hair
|
||||
const int HAIR_LINKS = 10; // Number of links in a hair strand
|
||||
const int HAIR_MAX_CONSTRAINTS = 2; // Hair verlet is connected to at most how many others
|
||||
|
||||
enum DriveKeys {
|
||||
FWD = 0,
|
||||
|
|
|
@ -195,7 +195,12 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
head->simulate(deltaTime, true);
|
||||
}
|
||||
|
||||
simulateHair(deltaTime);
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/hair Simulate");
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
simulateHair(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/ragdoll");
|
||||
|
@ -370,6 +375,7 @@ void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
if (!_shouldRender) {
|
||||
return; // exit early
|
||||
}
|
||||
|
||||
Avatar::render(cameraPosition, renderMode);
|
||||
|
||||
// don't display IK constraints in shadow mode
|
||||
|
@ -852,7 +858,9 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
|
|||
// Render head so long as the camera isn't inside it
|
||||
if (shouldRenderHead(Application::getInstance()->getCamera()->getPosition(), renderMode)) {
|
||||
getHead()->render(1.0f, modelRenderMode);
|
||||
renderHair();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::StringHair)) {
|
||||
renderHair();
|
||||
}
|
||||
}
|
||||
getHand()->render(true, modelRenderMode);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue