mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 19:53:30 +02:00
Merge pull request #1036 from PhilipRosedale/master
Added back particle clouds, made faster (rendering options->particle cloud)
This commit is contained in:
commit
3c212fb5f3
13 changed files with 300 additions and 28 deletions
|
@ -1987,6 +1987,11 @@ void Application::update(float deltaTime) {
|
|||
_myAvatar.simulate(deltaTime, NULL);
|
||||
}
|
||||
|
||||
// Simulate particle cloud movements
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) {
|
||||
_cloud.simulate(deltaTime);
|
||||
}
|
||||
|
||||
// no transmitter drive implies transmitter pick
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) {
|
||||
_transmitterPickStart = _myAvatar.getSkeleton().joint[AVATAR_JOINT_CHEST].position;
|
||||
|
@ -2083,8 +2088,7 @@ void Application::updateAvatar(float deltaTime) {
|
|||
_yawFromTouch = 0.f;
|
||||
|
||||
// Update my avatar's state from gyros and/or webcam
|
||||
_myAvatar.updateFromGyrosAndOrWebcam(Menu::getInstance()->isOptionChecked(MenuOption::GyroLook),
|
||||
_pitchFromTouch);
|
||||
_myAvatar.updateFromGyrosAndOrWebcam(_pitchFromTouch, Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead));
|
||||
|
||||
// Update head mouse from faceshift if active
|
||||
if (_faceshift.isActive()) {
|
||||
|
@ -2503,7 +2507,11 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
glDisable(GL_NORMALIZE);
|
||||
|
||||
//renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude());
|
||||
}
|
||||
}
|
||||
// Draw Cloud Particles
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) {
|
||||
_cloud.render();
|
||||
}
|
||||
// Draw voxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
|
@ -2513,6 +2521,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// restore default, white specular
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "Camera.h"
|
||||
#include "Cloud.h"
|
||||
#include "Environment.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
@ -263,6 +264,8 @@ private:
|
|||
|
||||
Stars _stars;
|
||||
|
||||
Cloud _cloud;
|
||||
|
||||
VoxelSystem _voxels;
|
||||
VoxelTree _clipboard; // if I copy/paste
|
||||
VoxelImporter _voxelImporter;
|
||||
|
|
85
interface/src/Cloud.cpp
Normal file
85
interface/src/Cloud.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// Cloud.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 11/17/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <InterfaceConfig.h>
|
||||
#include "Cloud.h"
|
||||
#include "Util.h"
|
||||
#include "Field.h"
|
||||
|
||||
const int NUM_PARTICLES = 100000;
|
||||
const float FIELD_COUPLE = 0.001f;
|
||||
const bool RENDER_FIELD = false;
|
||||
|
||||
Cloud::Cloud() {
|
||||
glm::vec3 box = glm::vec3(PARTICLE_WORLD_SIZE);
|
||||
_bounds = box;
|
||||
_count = NUM_PARTICLES;
|
||||
_particles = new Particle[_count];
|
||||
_field = new Field(PARTICLE_WORLD_SIZE, FIELD_COUPLE);
|
||||
|
||||
for (int i = 0; i < _count; i++) {
|
||||
_particles[i].position = randVector() * box;
|
||||
const float INIT_VEL_SCALE = 0.03f;
|
||||
_particles[i].velocity = randVector() * ((float)PARTICLE_WORLD_SIZE * INIT_VEL_SCALE);
|
||||
_particles[i].color = randVector();
|
||||
}
|
||||
}
|
||||
|
||||
void Cloud::render() {
|
||||
if (RENDER_FIELD) {
|
||||
_field->render();
|
||||
}
|
||||
|
||||
glPointSize(3.0f);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].position);
|
||||
glColorPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].color);
|
||||
glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
}
|
||||
|
||||
void Cloud::simulate (float deltaTime) {
|
||||
unsigned int i;
|
||||
_field->simulate(deltaTime);
|
||||
for (i = 0; i < _count; ++i) {
|
||||
|
||||
// Update position
|
||||
_particles[i].position += _particles[i].velocity * deltaTime;
|
||||
|
||||
// Decay Velocity (Drag)
|
||||
const float CONSTANT_DAMPING = 0.15f;
|
||||
_particles[i].velocity *= (1.f - CONSTANT_DAMPING * deltaTime);
|
||||
|
||||
// Interact with Field
|
||||
_field->interact(deltaTime, _particles[i].position, _particles[i].velocity);
|
||||
|
||||
// Update color to velocity
|
||||
_particles[i].color = (glm::normalize(_particles[i].velocity) * 0.5f) + 0.5f;
|
||||
|
||||
// Bounce at bounds
|
||||
if ((_particles[i].position.x > _bounds.x) || (_particles[i].position.x < 0.f)) {
|
||||
_particles[i].position.x = glm::clamp(_particles[i].position.x, 0.f, _bounds.x);
|
||||
_particles[i].velocity.x *= -1.f;
|
||||
}
|
||||
if ((_particles[i].position.y > _bounds.y) || (_particles[i].position.y < 0.f)) {
|
||||
_particles[i].position.y = glm::clamp(_particles[i].position.y, 0.f, _bounds.y);
|
||||
_particles[i].velocity.y *= -1.f;
|
||||
}
|
||||
if ((_particles[i].position.z > _bounds.z) || (_particles[i].position.z < 0.f)) {
|
||||
_particles[i].position.z = glm::clamp(_particles[i].position.z, 0.f, _bounds.z);
|
||||
_particles[i].velocity.z *= -1.f;
|
||||
}
|
||||
}
|
||||
}
|
32
interface/src/Cloud.h
Normal file
32
interface/src/Cloud.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Cloud.h
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 11/17/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Cloud__
|
||||
#define __interface__Cloud__
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
#define PARTICLE_WORLD_SIZE 256.0
|
||||
|
||||
class Cloud {
|
||||
public:
|
||||
Cloud();
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
private:
|
||||
struct Particle {
|
||||
glm::vec3 position, velocity, color;
|
||||
}* _particles;
|
||||
|
||||
unsigned int _count;
|
||||
glm::vec3 _bounds;
|
||||
Field* _field;
|
||||
};
|
||||
|
||||
#endif
|
100
interface/src/Field.cpp
Normal file
100
interface/src/Field.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Field.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 8/23/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// A vector-valued field over an array of elements arranged as a 3D lattice
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
int Field::value(float *value, float *pos) {
|
||||
int index = (int)(pos[0] / _worldSize * 10.0) +
|
||||
(int)(pos[1] / _worldSize * 10.0) * 10 +
|
||||
(int)(pos[2] / _worldSize * 10.0) * 100;
|
||||
|
||||
if ((index >= 0) && (index < FIELD_ELEMENTS)) {
|
||||
value[0] = _field[index].val.x;
|
||||
value[1] = _field[index].val.y;
|
||||
value[2] = _field[index].val.z;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Field::Field(float worldSize, float coupling) {
|
||||
_worldSize = worldSize;
|
||||
_coupling = coupling;
|
||||
//float fx, fy, fz;
|
||||
for (int i = 0; i < FIELD_ELEMENTS; i++) {
|
||||
const float FIELD_INITIAL_MAG = 0.0f;
|
||||
_field[i].val = randVector() * FIELD_INITIAL_MAG * _worldSize;
|
||||
_field[i].center.x = ((float)(i % 10) + 0.5f);
|
||||
_field[i].center.y = ((float)(i % 100 / 10) + 0.5f);
|
||||
_field[i].center.z = ((float)(i / 100) + 0.5f);
|
||||
_field[i].center *= _worldSize / 10.f;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Field::add(float* add, float *pos) {
|
||||
int index = (int)(pos[0] / _worldSize * 10.0) +
|
||||
(int)(pos[1] / _worldSize * 10.0) * 10 +
|
||||
(int)(pos[2] / _worldSize * 10.0) * 100;
|
||||
|
||||
if ((index >= 0) && (index < FIELD_ELEMENTS)) {
|
||||
_field[index].val.x += add[0];
|
||||
_field[index].val.y += add[1];
|
||||
_field[index].val.z += add[2];
|
||||
}
|
||||
}
|
||||
|
||||
void Field::interact(float deltaTime, const glm::vec3& pos, glm::vec3& vel) {
|
||||
|
||||
int index = (int)(pos.x / _worldSize * 10.0) +
|
||||
(int)(pos.y / _worldSize*10.0) * 10 +
|
||||
(int)(pos.z / _worldSize*10.0) * 100;
|
||||
if ((index >= 0) && (index < FIELD_ELEMENTS)) {
|
||||
vel += _field[index].val * deltaTime; // Particle influenced by field
|
||||
_field[index].val += vel * deltaTime * _coupling; // Field influenced by particle
|
||||
}
|
||||
}
|
||||
|
||||
void Field::simulate(float deltaTime) {
|
||||
glm::vec3 neighbors, add, diff;
|
||||
|
||||
for (int i = 0; i < FIELD_ELEMENTS; i++) {
|
||||
const float CONSTANT_DAMPING = 0.5f;
|
||||
_field[i].val *= (1.f - CONSTANT_DAMPING * deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Field::render() {
|
||||
int i;
|
||||
float scale_view = 0.05f * _worldSize;
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glBegin(GL_LINES);
|
||||
for (i = 0; i < FIELD_ELEMENTS; i++) {
|
||||
glColor3f(0, 1, 0);
|
||||
glVertex3fv(&_field[i].center.x);
|
||||
glVertex3f(_field[i].center.x + _field[i].val.x * scale_view,
|
||||
_field[i].center.y + _field[i].val.y * scale_view,
|
||||
_field[i].center.z + _field[i].val.z * scale_view);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glColor3f(0, 1, 0);
|
||||
glPointSize(4.0);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glBegin(GL_POINTS);
|
||||
for (i = 0; i < FIELD_ELEMENTS; i++) {
|
||||
glVertex3fv(&_field[i].center.x);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
|
46
interface/src/Field.h
Normal file
46
interface/src/Field.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Field.h
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 8/23/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__Field__
|
||||
#define __interface__Field__
|
||||
|
||||
#include <iostream>
|
||||
#include <glm/glm.hpp>
|
||||
#include "InterfaceConfig.h"
|
||||
#include "world.h"
|
||||
#include "Util.h"
|
||||
|
||||
const int FIELD_ELEMENTS = 1000;
|
||||
|
||||
/// Field is a lattice of vectors uniformly distributed in 3D with FIELD_ELEMENTS^(1/3) per side
|
||||
class Field {
|
||||
public:
|
||||
struct FieldElement {
|
||||
glm::vec3 val;
|
||||
glm::vec3 center;
|
||||
glm::vec3 fld;
|
||||
} _field[FIELD_ELEMENTS];
|
||||
|
||||
Field(float worldSize, float coupling);
|
||||
/// The field value at a position in space, given simply as the value of the enclosing cell
|
||||
int value(float *ret, float *pos);
|
||||
/// Visualize the field as vector lines drawn at each center
|
||||
void render();
|
||||
/// Add to the field value cell enclosing a location
|
||||
void add(float* add, float *loc);
|
||||
/// A particle with a position and velocity interacts with the field given the coupling
|
||||
/// constant passed when creating the field.
|
||||
void interact(float deltaTime, const glm::vec3& pos, glm::vec3& vel);
|
||||
/// Field evolves over timestep
|
||||
void simulate(float deltaTime);
|
||||
private:
|
||||
float _worldSize;
|
||||
float _coupling;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -212,7 +212,13 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
MenuOption::OffAxisProjection,
|
||||
0,
|
||||
false);
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu,
|
||||
MenuOption::TurnWithHead,
|
||||
0,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false);
|
||||
|
||||
|
||||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||
|
@ -234,6 +240,9 @@ Menu::Menu() :
|
|||
0,
|
||||
appInstance->getGlowEffect(),
|
||||
SLOT(cycleRenderMode()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false);
|
||||
|
||||
|
||||
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");
|
||||
|
||||
|
@ -312,12 +321,6 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::SimulateLeapHand);
|
||||
addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::TestRaveGlove);
|
||||
|
||||
|
||||
QMenu* gyroOptionsMenu = developerMenu->addMenu("Gyro Options");
|
||||
addCheckableActionToQMenuAndActionHash(gyroOptionsMenu, MenuOption::GyroLook, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(gyroOptionsMenu, MenuOption::HeadMouse);
|
||||
|
||||
|
||||
QMenu* trackingOptionsMenu = developerMenu->addMenu("Tracking Options");
|
||||
addCheckableActionToQMenuAndActionHash(trackingOptionsMenu,
|
||||
MenuOption::SkeletonTracking,
|
||||
|
|
|
@ -169,7 +169,7 @@ namespace MenuOption {
|
|||
const QString GoHome = "Go Home";
|
||||
const QString Gravity = "Use Gravity";
|
||||
const QString GroundPlane = "Ground Plane";
|
||||
const QString GyroLook = "Smooth Gyro Look";
|
||||
const QString ParticleCloud = "Particle Cloud";
|
||||
const QString ListenModeNormal = "Listen Mode Normal";
|
||||
const QString ListenModePoint = "Listen Mode Point";
|
||||
const QString ListenModeSingleSource = "Listen Mode Single Source";
|
||||
|
@ -181,6 +181,7 @@ namespace MenuOption {
|
|||
const QString NudgeVoxels = "Nudge";
|
||||
const QString OcclusionCulling = "Occlusion Culling";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString TurnWithHead = "Turn using Head";
|
||||
const QString Oscilloscope = "Audio Oscilloscope";
|
||||
const QString Pair = "Pair";
|
||||
const QString PasteVoxels = "Paste";
|
||||
|
|
|
@ -83,8 +83,6 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_mousePitch(0.f),
|
||||
_cameraYaw(_yaw),
|
||||
_isCameraMoving(false),
|
||||
_cameraFollowsHead(false),
|
||||
_cameraFollowHeadRate(0.0f),
|
||||
_face(this),
|
||||
_perlinFace(this),
|
||||
_blendFace(this)
|
||||
|
|
|
@ -57,7 +57,6 @@ public:
|
|||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; }
|
||||
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; }
|
||||
void setCameraFollowsHead(bool cameraFollowsHead) { _cameraFollowsHead = cameraFollowsHead; }
|
||||
|
||||
float getMousePitch() const { return _mousePitch; }
|
||||
void setMousePitch(float mousePitch) { _mousePitch = mousePitch; }
|
||||
|
@ -133,8 +132,6 @@ private:
|
|||
float _mousePitch;
|
||||
float _cameraYaw;
|
||||
bool _isCameraMoving;
|
||||
bool _cameraFollowsHead;
|
||||
float _cameraFollowHeadRate;
|
||||
Face _face;
|
||||
PerlinFace _perlinFace;
|
||||
BlendFace _blendFace;
|
||||
|
|
|
@ -357,8 +357,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
|
|||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
void MyAvatar::updateFromGyrosAndOrWebcam(bool gyroLook,
|
||||
float pitchFromTouch) {
|
||||
void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHead) {
|
||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||
SerialInterface* gyros = Application::getInstance()->getSerialHeadSensor();
|
||||
Webcam* webcam = Application::getInstance()->getWebcam();
|
||||
|
@ -368,11 +367,13 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool gyroLook,
|
|||
estimatedPosition = faceshift->getHeadTranslation();
|
||||
estimatedRotation = safeEulerAngles(faceshift->getHeadRotation());
|
||||
// Rotate the body if the head is turned quickly
|
||||
glm::vec3 headAngularVelocity = faceshift->getHeadAngularVelocity();
|
||||
const float FACESHIFT_YAW_VIEW_SENSITIVITY = 20.f;
|
||||
const float FACESHIFT_MIN_YAW_VELOCITY = 1.0f;
|
||||
if (fabs(headAngularVelocity.y) > FACESHIFT_MIN_YAW_VELOCITY) {
|
||||
_bodyYawDelta += headAngularVelocity.y * FACESHIFT_YAW_VIEW_SENSITIVITY;
|
||||
if (turnWithHead) {
|
||||
glm::vec3 headAngularVelocity = faceshift->getHeadAngularVelocity();
|
||||
const float FACESHIFT_YAW_VIEW_SENSITIVITY = 20.f;
|
||||
const float FACESHIFT_MIN_YAW_VELOCITY = 1.0f;
|
||||
if (fabs(headAngularVelocity.y) > FACESHIFT_MIN_YAW_VELOCITY) {
|
||||
_bodyYawDelta += headAngularVelocity.y * FACESHIFT_YAW_VIEW_SENSITIVITY;
|
||||
}
|
||||
}
|
||||
} else if (gyros->isActive()) {
|
||||
estimatedRotation = gyros->getEstimatedRotation();
|
||||
|
@ -429,7 +430,6 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool gyroLook,
|
|||
_head.setPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
_head.setYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
_head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
_head.setCameraFollowsHead(gyroLook);
|
||||
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = _scale * 0.5f;
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
|
||||
void reset();
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
void updateFromGyrosAndOrWebcam(bool gyroLook, float pitchFromTouch);
|
||||
void updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHead);
|
||||
void render(bool lookingInMirror, bool renderAvatarBalls);
|
||||
void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera);
|
||||
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
//
|
||||
// Created by Philip Rosedale on 8/23/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
// Simulation happens in positive cube with edge of size WORLD_SIZE
|
||||
//
|
||||
|
||||
#ifndef __interface__world__
|
||||
#define __interface__world__
|
||||
|
|
Loading…
Reference in a new issue