camera fixes for assets with large bounding boxes
This commit is contained in:
206
ios/src/camutils/FreeFlightManipulator.h
Normal file
206
ios/src/camutils/FreeFlightManipulator.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CAMUTILS_FREEFLIGHT_MANIPULATOR_H
|
||||
#define CAMUTILS_FREEFLIGHT_MANIPULATOR_H
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <math/scalar.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/quat.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace filament {
|
||||
namespace camutils {
|
||||
|
||||
using namespace filament::math;
|
||||
|
||||
template<typename FLOAT>
|
||||
class FreeFlightManipulator : public Manipulator<FLOAT> {
|
||||
public:
|
||||
using vec2 = filament::math::vec2<FLOAT>;
|
||||
using vec3 = filament::math::vec3<FLOAT>;
|
||||
using vec4 = filament::math::vec4<FLOAT>;
|
||||
using Bookmark = filament::camutils::Bookmark<FLOAT>;
|
||||
using Base = Manipulator<FLOAT>;
|
||||
using Config = typename Base::Config;
|
||||
|
||||
FreeFlightManipulator(Mode mode, const Config& props) : Base(mode, props) {
|
||||
setProperties(props);
|
||||
Base::mEye = Base::mProps.flightStartPosition;
|
||||
const auto pitch = Base::mProps.flightStartPitch;
|
||||
const auto yaw = Base::mProps.flightStartYaw;
|
||||
mTargetEuler = {pitch, yaw};
|
||||
updateTarget(pitch, yaw);
|
||||
}
|
||||
|
||||
void setProperties(const Config& props) override {
|
||||
Config resolved = props;
|
||||
|
||||
if (resolved.flightPanSpeed == vec2(0, 0)) {
|
||||
resolved.flightPanSpeed = vec2(0.01, 0.01);
|
||||
}
|
||||
if (resolved.flightMaxSpeed == 0.0) {
|
||||
resolved.flightMaxSpeed = 10.0;
|
||||
}
|
||||
if (resolved.flightSpeedSteps == 0) {
|
||||
resolved.flightSpeedSteps = 80;
|
||||
}
|
||||
|
||||
Base::setProperties(resolved);
|
||||
}
|
||||
|
||||
void updateTarget(FLOAT pitch, FLOAT yaw) {
|
||||
Base::mTarget = Base::mEye + (mat3::eulerZYX(0, yaw, pitch) * vec3(0.0, 0.0, -1.0));
|
||||
}
|
||||
|
||||
void grabBegin(int x, int y, bool strafe) override {
|
||||
mGrabWin = {x, y};
|
||||
mGrabbing = true;
|
||||
mGrabEuler = mTargetEuler;
|
||||
}
|
||||
|
||||
void grabUpdate(int x, int y) override {
|
||||
if (!mGrabbing) {
|
||||
return;
|
||||
}
|
||||
|
||||
const vec2 del = mGrabWin - vec2{x, y};
|
||||
|
||||
const auto& grabPitch = mGrabEuler.x;
|
||||
const auto& grabYaw = mGrabEuler.y;
|
||||
auto& pitch = mTargetEuler.x;
|
||||
auto& yaw = mTargetEuler.y;
|
||||
|
||||
constexpr double EPSILON = 0.001;
|
||||
|
||||
auto panSpeed = Base::mProps.flightPanSpeed;
|
||||
constexpr FLOAT minPitch = (-F_PI_2 + EPSILON);
|
||||
constexpr FLOAT maxPitch = ( F_PI_2 - EPSILON);
|
||||
pitch = clamp(grabPitch + del.y * -panSpeed.y, minPitch, maxPitch);
|
||||
yaw = fmod(grabYaw + del.x * panSpeed.x, 2.0 * F_PI);
|
||||
|
||||
updateTarget(pitch, yaw);
|
||||
}
|
||||
|
||||
void grabEnd() override {
|
||||
mGrabbing = false;
|
||||
}
|
||||
|
||||
void keyDown(typename Base::Key key) override {
|
||||
mKeyDown[(int) key] = true;
|
||||
}
|
||||
|
||||
void keyUp(typename Base::Key key) override {
|
||||
mKeyDown[(int) key] = false;
|
||||
}
|
||||
|
||||
void scroll(int x, int y, FLOAT scrolldelta) override {
|
||||
const FLOAT halfSpeedSteps = Base::mProps.flightSpeedSteps / 2;
|
||||
mScrollWheel = clamp(mScrollWheel + scrolldelta, -halfSpeedSteps, halfSpeedSteps);
|
||||
// Normalize the scroll position from -1 to 1 and calculate the move speed, in world
|
||||
// units per second.
|
||||
mScrollPositionNormalized = (mScrollWheel + halfSpeedSteps) / halfSpeedSteps - 1.0;
|
||||
mMoveSpeed = pow(Base::mProps.flightMaxSpeed, mScrollPositionNormalized);
|
||||
}
|
||||
|
||||
void update(FLOAT deltaTime) override {
|
||||
vec3 forceLocal { 0.0, 0.0, 0.0 };
|
||||
|
||||
if (mKeyDown[(int) Base::Key::FORWARD]) {
|
||||
forceLocal += vec3{ 0.0, 0.0, -1.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::LEFT]) {
|
||||
forceLocal += vec3{ -1.0, 0.0, 0.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::BACKWARD]) {
|
||||
forceLocal += vec3{ 0.0, 0.0, 1.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::RIGHT]) {
|
||||
forceLocal += vec3{ 1.0, 0.0, 0.0 };
|
||||
}
|
||||
|
||||
const mat4 orientation = mat4::lookAt(Base::mEye, Base::mTarget, Base::mProps.upVector);
|
||||
vec3 forceWorld = (orientation * vec4{ forceLocal, 0.0f }).xyz;
|
||||
|
||||
if (mKeyDown[(int) Base::Key::UP]) {
|
||||
forceWorld += vec3{ 0.0, 1.0, 0.0 };
|
||||
}
|
||||
if (mKeyDown[(int) Base::Key::DOWN]) {
|
||||
forceWorld += vec3{ 0.0, -1.0, 0.0 };
|
||||
}
|
||||
|
||||
forceWorld *= mMoveSpeed;
|
||||
|
||||
const auto dampingFactor = Base::mProps.flightMoveDamping;
|
||||
if (dampingFactor == 0.0) {
|
||||
// Without damping, we simply treat the force as our velocity.
|
||||
mEyeVelocity = forceWorld;
|
||||
} else {
|
||||
// The dampingFactor acts as "friction", which acts upon the camera in the direction
|
||||
// opposite its velocity.
|
||||
// Force is also multiplied by the dampingFactor, to "make up" for the friction.
|
||||
// This ensures that the max velocity still approaches mMoveSpeed;
|
||||
vec3 velocityDelta = (forceWorld - mEyeVelocity) * dampingFactor;
|
||||
mEyeVelocity += velocityDelta * deltaTime;
|
||||
}
|
||||
|
||||
const vec3 positionDelta = mEyeVelocity * deltaTime;
|
||||
|
||||
Base::mEye += positionDelta;
|
||||
Base::mTarget += positionDelta;
|
||||
}
|
||||
|
||||
Bookmark getCurrentBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.flight.position = Base::mEye;
|
||||
bookmark.flight.pitch = mTargetEuler.x;
|
||||
bookmark.flight.yaw = mTargetEuler.y;
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
Bookmark getHomeBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.flight.position = Base::mProps.flightStartPosition;
|
||||
bookmark.flight.pitch = Base::mProps.flightStartPitch;
|
||||
bookmark.flight.yaw = Base::mProps.flightStartYaw;
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
void jumpToBookmark(const Bookmark& bookmark) override {
|
||||
Base::mEye = bookmark.flight.position;
|
||||
updateTarget(bookmark.flight.pitch, bookmark.flight.yaw);
|
||||
}
|
||||
|
||||
private:
|
||||
vec2 mGrabWin;
|
||||
vec2 mTargetEuler; // (pitch, yaw)
|
||||
vec2 mGrabEuler; // (pitch, yaw)
|
||||
bool mKeyDown[(int) Base::Key::COUNT] = {false};
|
||||
bool mGrabbing = false;
|
||||
FLOAT mScrollWheel = 0.0f;
|
||||
FLOAT mScrollPositionNormalized = 0.0f;
|
||||
FLOAT mMoveSpeed = 1.0f;
|
||||
vec3 mEyeVelocity;
|
||||
};
|
||||
|
||||
} // namespace camutils
|
||||
} // namespace filament
|
||||
|
||||
#endif /* CAMUTILS_FREEFLIGHT_MANIPULATOR_H */
|
||||
Reference in New Issue
Block a user