Files
filament/samples/app/CameraManipulator.cpp
Romain Guy 39ca6d146f Fix ambiguities with translate() and scale() (#154)
These two functions expect a vector of the same size as the
matrix's storage vectors (float4 for a mat4f for instance) which
has two major issues:

- The vector must end with 1 for homogeneous coordinates to work
- Passing a single scalar (mat4f::scale(0.5)) creates a matrix
  whose diagonal is set to that scalar, thus breaking homogeneous
  coordinates

With this change scale and translate expect a vector who dimensionality
is 1 less that of the matrix's underlying storage vectors. i.e. a float3
for mat4f.
2018-08-27 10:21:13 -07:00

140 lines
4.5 KiB
C++

/*
* Copyright (C) 2015 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.
*/
#include "CameraManipulator.h"
using namespace math;
template <typename T>
static constexpr inline double radians(T deg) {
return deg * (M_PI / 180.0);
}
static inline double3 rotateVector(double rx, double ry, const double3& v) {
return (mat3::rotate(ry, double3{ 0, 1, 0}) * mat3::rotate(rx, double3{ 1, 0, 0})) * v;
}
//------------------------------------------------------------------------------
CameraManipulator::CameraManipulator() = default;
CameraManipulator::CameraManipulator(Camera* camera, size_t width, size_t height)
: mCamera(camera), mWidth(width), mHeight(height), mAspect(double(width)/height) {
lookAt(double3(0), double3(0,0,-1));
}
void CameraManipulator::setCamera(Camera* camera) {
mCamera = camera;
}
void CameraManipulator::setViewport(size_t w, size_t h) {
mWidth = w;
mHeight = h;
mAspect = double(w)/h;
}
//------------------------------------------------------------------------------
void CameraManipulator::lookAt(const double3& eye, const double3& at) {
mTranslation = eye;
double3 dt = at - eye;
double yz_length = std::sqrt((dt.y * dt.y) + (dt.z * dt.z));
mRotation.z = 0.0;
mRotation.x = std::atan2(dt.y, -dt.z);
mRotation.y = std::atan2(dt.x, yz_length);
mCenterOfInterest = -length(dt);
updateCameraTransform();
}
//------------------------------------------------------------------------------
void CameraManipulator::track(const double2& delta) {
double3 d_s = rotateVector(mRotation.x, mRotation.y, { 1.0, 0.0, 0.0});
double3 d_t = rotateVector(mRotation.x, mRotation.y, { 0.0, 1.0, 0.0});
double mult_t = 2.0 * mCenterOfInterest * std::tan(radians(mFovx) / 2.0);
double mult_s = mult_t / mWidth;
mult_t /= mHeight;
double s = mult_s * delta.x;
double t = mult_t * delta.y;
mTranslation += (s * d_s) + (t * d_t);
updateCameraTransform();
}
//------------------------------------------------------------------------------
void CameraManipulator::dolly(double delta, double dolly_speed) {
double3 eye = mTranslation;
double3 v = rotateVector(mRotation.x, mRotation.y, { 0.0, 0.0, mCenterOfInterest});
double3 view = eye + v;
// Magic dolly function
v = normalize(v);
double t = delta / mWidth;
double dolly_by = 1.0 - std::exp(-dolly_speed * t);
dolly_by *= mCenterOfInterest;
double3 new_eye = eye + (dolly_by * v);
mTranslation = new_eye;
v = new_eye - view;
mCenterOfInterest = -length(v);
updateCameraTransform();
}
void CameraManipulator::rotate(const double2& delta, double rotate_speed) {
double rot_x = mRotation.x;
double rot_y = mRotation.y;
double rot_z = mRotation.z;
double3 eye = mTranslation;
double3 view = eye + rotateVector(rot_x, rot_y, { 0.0, 0.0, mCenterOfInterest});
rot_y += rotate_speed * (-delta.x / mWidth);
rot_x += rotate_speed * ( delta.y / mHeight);
mTranslation = view + rotateVector(rot_x, rot_y, {0.0, 0.0, -mCenterOfInterest});
mRotation = double3(rot_x, rot_y, rot_z);
updateCameraTransform();
}
void CameraManipulator::updateCameraTransform() {
if (mCamera) {
mat4 rotate_z = mat4::rotate(mRotation.z, double3(0, 0, 1));
mat4 rotate_x = mat4::rotate(mRotation.x, double3(1, 0, 0));
mat4 rotate_y = mat4::rotate(mRotation.y, double3(0, 1, 0));
mat4 translate = mat4::translate(mTranslation);
mat4 view = translate * (rotate_y * rotate_x * rotate_z);
mCamera->setModelMatrix(mat4f(view));
if (mCameraChanged) {
mCameraChanged(mCamera);
}
}
}
void CameraManipulator::updateCameraProjection() {
if (mCamera) {
mCamera->setProjection(mFovx, mAspect, mClipNear, mClipFar);
if (mCameraChanged) {
mCameraChanged(mCamera);
}
}
}
void CameraManipulator::setCameraChangedCallback(CameraManipulator::CameraChangedCallback cb) {
mCameraChanged = cb;
}