mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into away
This commit is contained in:
commit
4a54f2052e
12 changed files with 79 additions and 135 deletions
|
@ -176,6 +176,9 @@ function MyController(hand) {
|
|||
this.pointer = null; // entity-id of line object
|
||||
this.triggerValue = 0; // rolling average of trigger value
|
||||
this.rawTriggerValue = 0;
|
||||
|
||||
this.offsetPosition = { x: 0.0, y: 0.0, z: 0.0 };
|
||||
this.offsetRotation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 };
|
||||
|
||||
var _this = this;
|
||||
|
||||
|
@ -291,7 +294,7 @@ function MyController(hand) {
|
|||
return this.triggerValue < TRIGGER_OFF_VALUE;
|
||||
};
|
||||
|
||||
this.triggerSqueezed = function() {
|
||||
this.triggerSqueezed = function() {
|
||||
var triggerValue = this.rawTriggerValue;
|
||||
return triggerValue > TRIGGER_ON_VALUE;
|
||||
};
|
||||
|
@ -352,7 +355,7 @@ function MyController(hand) {
|
|||
|
||||
var intersection = Entities.findRayIntersection(pickRayBacked, true);
|
||||
|
||||
if (intersection.intersects && !intersection.properties.locked) {
|
||||
if (intersection.intersects) {
|
||||
// the ray is intersecting something we can move.
|
||||
var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
|
||||
this.grabbedEntity = intersection.entityID;
|
||||
|
@ -369,7 +372,7 @@ function MyController(hand) {
|
|||
disabledHand = 'none';
|
||||
}
|
||||
|
||||
if (!grabbableData.grabbable) {
|
||||
if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) {
|
||||
this.grabbedEntity = null;
|
||||
continue;
|
||||
}
|
||||
|
@ -379,10 +382,9 @@ function MyController(hand) {
|
|||
}
|
||||
if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) {
|
||||
// the hand is very close to the intersected object. go into close-grabbing mode.
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
if (grabbableData.wantsTrigger) {
|
||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||
} else {
|
||||
} else if (!intersection.properties.locked) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
}
|
||||
} else {
|
||||
|
@ -391,7 +393,8 @@ function MyController(hand) {
|
|||
this.grabbedEntity = null;
|
||||
} else {
|
||||
// the hand is far from the intersected object. go into distance-holding mode
|
||||
if (intersection.properties.collisionsWillMove) {
|
||||
if (intersection.properties.collisionsWillMove
|
||||
&& !intersection.properties.locked) {
|
||||
this.setState(STATE_DISTANCE_HOLDING);
|
||||
} else {
|
||||
this.setState(STATE_FAR_GRABBING_NON_COLLIDING);
|
||||
|
@ -503,7 +506,7 @@ function MyController(hand) {
|
|||
|
||||
// How far did the avatar turn this timestep?
|
||||
// Note: The following code is too long because we need a Quat.quatBetween() function
|
||||
// that returns the minimum quaternion between two quaternions.
|
||||
// that returns the minimum quaternion between two quaternions.
|
||||
var currentOrientation = MyAvatar.orientation;
|
||||
if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) {
|
||||
var negativeCurrentOrientation = {
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
// createBoxes.js
|
||||
// part of bubblewand
|
||||
//
|
||||
// Created by James B. Pollack @imgntn -- 09/07/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Loads a wand model and attaches the bubble wand behavior.
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
|
||||
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
|
||||
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
|
||||
|
||||
var bubbleModel = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx?' + randInt(0, 10000);;
|
||||
//var scriptURL'http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/wand.js?'+randInt(0,10000);
|
||||
|
||||
//for local testing
|
||||
//var scriptURL = "http://localhost:8080/scripts/setRecurringTimeout.js?" + randInt(0, 10000);
|
||||
|
||||
|
||||
var scriptURL='http://hifi-public.s3.amazonaws.com/james/debug/timeouts/setRecurringTimeout.js?'+ randInt(0, 10000);
|
||||
//create the wand in front of the avatar
|
||||
|
||||
var boxes=[];
|
||||
var TEST_ENTITY_NAME = "TimerScript";
|
||||
|
||||
|
||||
var TOTAL_ENTITIES = 100;
|
||||
for (var i = 0; i < TOTAL_ENTITIES; i++) {
|
||||
var box = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: TEST_ENTITY_NAME,
|
||||
position: {
|
||||
x: randInt(0, 100) - 50 + MyAvatar.position.x,
|
||||
y: randInt(0, 100) - 50 + MyAvatar.position.x,
|
||||
z: randInt(0, 100) - 50 + MyAvatar.position.x,
|
||||
},
|
||||
dimensions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1,
|
||||
},
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
//must be enabled to be grabbable in the physics engine
|
||||
collisionsWillMove: true,
|
||||
shapeType: 'box',
|
||||
lifetime:60,
|
||||
script: scriptURL
|
||||
});
|
||||
boxes.push(box)
|
||||
}
|
||||
|
||||
|
||||
function cleanup() {
|
||||
while (boxes.length > 0) {
|
||||
Entities.deleteEntity(boxes.pop());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"name": "Vive to Standard",
|
||||
"channels": [
|
||||
{ "from": "Vive.LY", "filters": [ "invert", { "type": "deadZone", "min": 0.7 } ], "to": "Standard.LY" },
|
||||
{ "from": "Vive.LX", "filters": { "type": "deadZone", "min": 0.7 }, "to": "Standard.LX" },
|
||||
{ "from": "Vive.LY", "when": "Vive.LS", "filters": "invert", "to": "Standard.LY" },
|
||||
{ "from": "Vive.LX", "when": "Vive.LS", "to": "Standard.LX" },
|
||||
|
||||
{ "from": "Vive.LT", "to": "Standard.LT" },
|
||||
{ "from": "Vive.LB", "to": "Standard.LB" },
|
||||
{ "from": "Vive.LS", "to": "Standard.LS" },
|
||||
|
||||
{ "from": "Vive.RY", "filters": "invert", "to": "Standard.RY" },
|
||||
{ "from": "Vive.RX", "to": "Standard.RX" },
|
||||
{ "from": "Vive.RY", "when": "Vive.RS", "filters": "invert", "to": "Standard.RY" },
|
||||
{ "from": "Vive.RX", "when": "Vive.RS", "to": "Standard.RX" },
|
||||
|
||||
{ "from": "Vive.RT", "to": "Standard.RT" },
|
||||
{ "from": "Vive.RB", "to": "Standard.RB" },
|
||||
|
|
|
@ -159,8 +159,7 @@ static QTimer locationUpdateTimer;
|
|||
static QTimer balanceUpdateTimer;
|
||||
static QTimer identityPacketTimer;
|
||||
static QTimer billboardPacketTimer;
|
||||
static QTimer checkFPStimer;
|
||||
static QTimer idleTimer;
|
||||
static QTimer pingTimer;
|
||||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
static const QString SVO_EXTENSION = ".svo";
|
||||
|
@ -184,9 +183,7 @@ static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS
|
|||
static const QString INFO_HELP_PATH = "html/interface-welcome.html";
|
||||
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
|
||||
|
||||
static const unsigned int TARGET_SIM_FRAMERATE = 60;
|
||||
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
||||
static const int TARGET_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / TARGET_SIM_FRAMERATE;
|
||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||
|
||||
#ifndef __APPLE__
|
||||
|
@ -843,8 +840,7 @@ void Application::cleanupBeforeQuit() {
|
|||
balanceUpdateTimer.stop();
|
||||
identityPacketTimer.stop();
|
||||
billboardPacketTimer.stop();
|
||||
checkFPStimer.stop();
|
||||
idleTimer.stop();
|
||||
pingTimer.stop();
|
||||
QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection);
|
||||
|
||||
// save state
|
||||
|
@ -979,12 +975,9 @@ void Application::initializeGL() {
|
|||
_entityEditSender.initialize(_enableProcessOctreeThread);
|
||||
|
||||
// call our timer function every second
|
||||
connect(&checkFPStimer, &QTimer::timeout, this, &Application::checkFPS);
|
||||
checkFPStimer.start(1000);
|
||||
connect(&pingTimer, &QTimer::timeout, this, &Application::ping);
|
||||
pingTimer.start(1000);
|
||||
|
||||
// call our idle function whenever we can
|
||||
connect(&idleTimer, &QTimer::timeout, this, &Application::idle);
|
||||
idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS);
|
||||
_idleLoopStdev.reset();
|
||||
|
||||
// update before the first render
|
||||
|
@ -1048,6 +1041,26 @@ void Application::initializeUi() {
|
|||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
_frameCount++;
|
||||
|
||||
// update fps moving average
|
||||
uint64_t now = usecTimestampNow();
|
||||
static uint64_t lastPaintBegin{ now };
|
||||
uint64_t diff = now - lastPaintBegin;
|
||||
if (diff != 0) {
|
||||
_framesPerSecond.updateAverage((float)USECS_PER_SECOND / (float)diff);
|
||||
}
|
||||
|
||||
lastPaintBegin = now;
|
||||
|
||||
// update fps once a second
|
||||
if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) {
|
||||
_fps = _framesPerSecond.getAverage();
|
||||
_lastFramesPerSecondUpdate = now;
|
||||
}
|
||||
|
||||
idle(now);
|
||||
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
|
||||
|
@ -1314,7 +1327,6 @@ void Application::paintGL() {
|
|||
{
|
||||
PerformanceTimer perfTimer("makeCurrent");
|
||||
_offscreenContext->makeCurrent();
|
||||
_frameCount++;
|
||||
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||
|
||||
// Reset the gpu::Context Stages
|
||||
|
@ -2087,20 +2099,14 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Every second, check the frame rates and other stuff
|
||||
void Application::checkFPS() {
|
||||
// Every second, send a ping, if menu item is checked.
|
||||
void Application::ping() {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
DependencyManager::get<NodeList>()->sendPingPackets();
|
||||
}
|
||||
|
||||
float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
|
||||
|
||||
_fps = (float)_frameCount / diffTime;
|
||||
_frameCount = 0;
|
||||
_timerStart.start();
|
||||
}
|
||||
|
||||
void Application::idle() {
|
||||
void Application::idle(uint64_t now) {
|
||||
if (_aboutToQuit) {
|
||||
return; // bail early, nothing to do here.
|
||||
}
|
||||
|
@ -2123,7 +2129,6 @@ void Application::idle() {
|
|||
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
uint64_t now = usecTimestampNow();
|
||||
static uint64_t lastIdleStart{ now };
|
||||
uint64_t idleStartToStartDuration = now - lastIdleStart;
|
||||
if (idleStartToStartDuration != 0) {
|
||||
|
|
|
@ -306,8 +306,8 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void clearDomainOctreeDetails();
|
||||
void checkFPS();
|
||||
void idle();
|
||||
void ping();
|
||||
void idle(uint64_t now);
|
||||
void aboutToQuit();
|
||||
|
||||
void handleScriptEngineLoaded(const QString& scriptFilename);
|
||||
|
@ -541,6 +541,8 @@ private:
|
|||
EntityItemID _keyboardFocusedItem;
|
||||
quint64 _lastAcceptedKeyPress = 0;
|
||||
|
||||
SimpleMovingAverage _framesPerSecond{10};
|
||||
quint64 _lastFramesPerSecondUpdate = 0;
|
||||
SimpleMovingAverage _simsPerSecond{10};
|
||||
int _simsPerSecondReport = 0;
|
||||
quint64 _lastSimsPerSecondUpdate = 0;
|
||||
|
|
|
@ -661,6 +661,9 @@ void Avatar::updateJointMappings() {
|
|||
}
|
||||
|
||||
void Avatar::renderBillboard(RenderArgs* renderArgs) {
|
||||
// FIXME disabling the billboard because it doesn't appear to work reliably
|
||||
// the billboard is ending up with a random texture and position.
|
||||
return;
|
||||
if (_billboard.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -286,10 +286,10 @@ void AvatarManager::handleOutgoingChanges(const VectorOfMotionStates& motionStat
|
|||
|
||||
void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents) {
|
||||
for (Collision collision : collisionEvents) {
|
||||
// TODO: Current physics uses null idA or idB for non-entities. The plan is to handle MOTIONSTATE_TYPE_AVATAR,
|
||||
// and then MOTIONSTATE_TYPE_MYAVATAR. As it is, this code only covers the case of my avatar (in which case one
|
||||
// if the ids will be null), and the behavior for other avatars is not specified. This has to be fleshed
|
||||
// out as soon as we use the new motionstates.
|
||||
// TODO: The plan is to handle MOTIONSTATE_TYPE_AVATAR, and then MOTIONSTATE_TYPE_MYAVATAR. As it is, other
|
||||
// people's avatars will have an id that doesn't match any entities, and one's own avatar will have
|
||||
// an id of null. Thus this code handles any collision in which one of the participating objects is
|
||||
// my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
|
||||
if (collision.idA.isNull() || collision.idB.isNull()) {
|
||||
MyAvatar* myAvatar = getMyAvatar();
|
||||
const QString& collisionSoundURL = myAvatar->getCollisionSoundURL();
|
||||
|
@ -299,9 +299,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
|
||||
|
||||
if (!isSound) {
|
||||
// TODO: When the new motion states are used, we'll probably break from the whole loop as soon as we hit our own avatar
|
||||
// (regardless of isSound), because other users should inject for their own avatars.
|
||||
continue;
|
||||
return; // No sense iterating for others. We only have one avatar.
|
||||
}
|
||||
// Your avatar sound is personal to you, so let's say the "mass" part of the kinetic energy is already accounted for.
|
||||
const float energy = velocityChange * velocityChange;
|
||||
|
@ -314,7 +312,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
|
||||
AudioInjector::playSound(collisionSoundURL, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
|
||||
myAvatar->collisionWithEntity(collision);
|
||||
}
|
||||
return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
assert(_avatar);
|
||||
_type = MOTIONSTATE_TYPE_AVATAR;
|
||||
if (_shape) {
|
||||
_mass = 100.0f; // HACK
|
||||
}
|
||||
|
|
|
@ -121,6 +121,8 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||
this, &MyAvatar::goToLocation);
|
||||
_characterController.setEnabled(true);
|
||||
|
||||
_bodySensorMatrix = deriveBodyFromHMDSensor();
|
||||
}
|
||||
|
||||
MyAvatar::~MyAvatar() {
|
||||
|
@ -345,23 +347,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
}
|
||||
|
||||
void MyAvatar::updateHMDFollowVelocity() {
|
||||
bool isMoving;
|
||||
if (_lastIsMoving) {
|
||||
const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
|
||||
isMoving = glm::length(_velocity) >= MOVE_EXIT_SPEED_THRESHOLD;
|
||||
} else {
|
||||
const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec
|
||||
isMoving = glm::length(_velocity) > MOVE_ENTER_SPEED_THRESHOLD;
|
||||
}
|
||||
|
||||
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
|
||||
_lastIsMoving = isMoving;
|
||||
|
||||
bool hmdIsAtRest = _hmdAtRestDetector.update(_hmdSensorPosition, _hmdSensorOrientation);
|
||||
if (hmdIsAtRest || justStartedMoving) {
|
||||
_isFollowingHMD = true;
|
||||
}
|
||||
|
||||
// compute offset to body's target position (in sensor-frame)
|
||||
auto sensorBodyMatrix = deriveBodyFromHMDSensor();
|
||||
_hmdFollowOffset = extractTranslation(sensorBodyMatrix) - extractTranslation(_bodySensorMatrix);
|
||||
|
@ -370,13 +355,29 @@ void MyAvatar::updateHMDFollowVelocity() {
|
|||
// don't pull the body DOWN to match the target (allow animation system to squat)
|
||||
truncatedOffset.y = 0.0f;
|
||||
}
|
||||
float truncatedOffsetDistance = glm::length(truncatedOffset);
|
||||
|
||||
bool isMoving;
|
||||
if (_lastIsMoving) {
|
||||
const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
|
||||
isMoving = glm::length(_velocity) >= MOVE_EXIT_SPEED_THRESHOLD;
|
||||
} else {
|
||||
const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec
|
||||
isMoving = glm::length(_velocity) > MOVE_ENTER_SPEED_THRESHOLD;
|
||||
}
|
||||
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
|
||||
_lastIsMoving = isMoving;
|
||||
bool hmdIsAtRest = _hmdAtRestDetector.update(_hmdSensorPosition, _hmdSensorOrientation);
|
||||
const float MIN_HMD_HIP_SHIFT = 0.05f;
|
||||
if (justStartedMoving || (hmdIsAtRest && truncatedOffsetDistance > MIN_HMD_HIP_SHIFT)) {
|
||||
_isFollowingHMD = true;
|
||||
}
|
||||
|
||||
bool needNewFollowSpeed = (_isFollowingHMD && _hmdFollowSpeed == 0.0f);
|
||||
if (!needNewFollowSpeed) {
|
||||
// check to see if offset has exceeded its threshold
|
||||
float distance = glm::length(truncatedOffset);
|
||||
const float MAX_HMD_HIP_SHIFT = 0.2f;
|
||||
if (distance > MAX_HMD_HIP_SHIFT) {
|
||||
if (truncatedOffsetDistance > MAX_HMD_HIP_SHIFT) {
|
||||
_isFollowingHMD = true;
|
||||
needNewFollowSpeed = true;
|
||||
}
|
||||
|
|
|
@ -152,7 +152,6 @@ public slots:
|
|||
Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords);
|
||||
|
||||
signals:
|
||||
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
|
||||
void canAdjustLocksChanged(bool canAdjustLocks);
|
||||
|
|
|
@ -360,16 +360,16 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
|
|||
glm::vec3 velocityChange = (motionStateA ? motionStateA->getObjectLinearVelocityChange() : glm::vec3(0.0f)) +
|
||||
(motionStateB ? motionStateB->getObjectLinearVelocityChange() : glm::vec3(0.0f));
|
||||
|
||||
if (motionStateA && motionStateA->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
||||
if (motionStateA) {
|
||||
QUuid idA = motionStateA->getObjectID();
|
||||
QUuid idB;
|
||||
if (motionStateB && motionStateB->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
||||
if (motionStateB) {
|
||||
idB = motionStateB->getObjectID();
|
||||
}
|
||||
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnB()) + _originOffset;
|
||||
glm::vec3 penetration = bulletToGLM(contact.distance * contact.normalWorldOnB);
|
||||
_collisionEvents.push_back(Collision(type, idA, idB, position, penetration, velocityChange));
|
||||
} else if (motionStateB && motionStateB->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
||||
} else if (motionStateB) {
|
||||
QUuid idB = motionStateB->getObjectID();
|
||||
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnA()) + _originOffset;
|
||||
// NOTE: we're flipping the order of A and B (so that the first objectID is never NULL)
|
||||
|
|
|
@ -84,7 +84,7 @@ private:
|
|||
const glm::vec3& TWO() { return Vectors::TWO; }
|
||||
const glm::vec3& HALF() { return Vectors::HALF; }
|
||||
const glm::vec3& RIGHT() { return Vectors::RIGHT; }
|
||||
const glm::vec3& UP() { return Vectors::UNIT_X; }
|
||||
const glm::vec3& UP() { return Vectors::UP; }
|
||||
const glm::vec3& FRONT() { return Vectors::FRONT; }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue