c ++ – A camera controller API for my game engine

As a hobby I work on a game engine to learn C ++ and graphics programming. Now I have completed my first iteration of my camera system with OpengGL and GLM. Since I'm mostly self-taught, I'm looking for feedback.

I'm mainly looking for feedback on the following:

  • Is the API easy for another user to understand / implement?
  • Are there obvious performance issues?
  • Are there any missing features that you suspect are in a camera controller?
  • Is the API consistent in terms of code style and practices?

But of course any other feedback is also very welcome!

Perspective camera
Low level, responsible for the projection matrix

// PerspectiveCamera.h
#ifndef CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_
#define CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_

#include "Core/Core.h"
#include "Events/ApplicationEvents.h"
#include "Camera.h"

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

namespace cheetah
{
    struct PerspectiveCameraParams
    {
        const float radians = 45.0f;
        const float zNear = -1.0f;
        const float zFar = 1.0f;
        const float aspectRatio;
        const float zoom;
        const glm::vec3 position = glm::vec3(0.0f);
        const glm::vec3 rotationAxis = glm::vec3(1.0f);
        const float rotationDegrees = 0.0f;
    };

    class CH_API PerspectiveCamera : public Camera
    {
    public:
        PerspectiveCamera(const PerspectiveCameraParams& params);


        inline glm::mat4 getViewProjectionMatrix() const override { return m_viewProjectionMatrix; };
        inline glm::mat4 getProjectionMatrix() const override { return m_projectionMatrix; };
        inline glm::mat4 getViewMatrix() const override { return m_viewMatrix; };
        inline float getZoom() const override { return m_zoom; };
        inline float getAspectRatio() const override { return m_aspectRatio; };

        void setZoom(const float& zoom) override;
        void setAspectRatio(const float& aspectRatio) override;
        void setViewMatrix(const glm::mat4& viewMatrix) override;

        void recalculateViewProjectionMatrix() override;

    private:
        float m_aspectRatio;
        float m_zoom;
        float m_zNear;
        float m_zFar;
        float m_radians;
        glm::mat4 m_projectionMatrix;
        glm::mat4 m_viewMatrix;
        glm::mat4 m_viewProjectionMatrix;
    };
}

#endif // !CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_
// PerspectiveCamera.cpp
#include "PerspectiveCamera.h"

namespace cheetah
{
    PerspectiveCamera::PerspectiveCamera(const PerspectiveCameraParams& params)
        :
        m_projectionMatrix(glm::perspective(glm::radians(params.radians), params.aspectRatio, params.zNear, params.zFar)),
        m_viewMatrix(glm::rotate(glm::translate(glm::mat4(1.0f), params.position), params.rotationDegrees, params.rotationAxis)),
        m_viewProjectionMatrix(m_projectionMatrix* m_viewMatrix),
        m_aspectRatio(params.aspectRatio),
        m_zoom(params.zoom),
        m_zNear(params.zNear),
        m_zFar(params.zFar),
        m_radians(params.radians)
    {
    }

    void PerspectiveCamera::setViewMatrix(const glm::mat4& viewMatrix)
    {
        m_viewMatrix = viewMatrix;
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setZoom(const float& zoom)
    {
        m_zoom = zoom;
        m_projectionMatrix = glm::perspective(glm::radians(m_radians += m_zoom), m_aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setAspectRatio(const float& aspectRatio)
    {
        m_aspectRatio = aspectRatio;
        m_projectionMatrix = glm::perspective(glm::radians(m_radians), aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::recalculateViewProjectionMatrix()
    {
        m_viewProjectionMatrix = m_projectionMatrix * m_viewMatrix;
    }
}

CameraController
Higher level, doesn't care about camera type (ortho or perspective)

// CameraController.h
#ifndef CHEETAH_ENGINE_RENDERER_CAMERACONTROLLER_H_
#define CHEETAH_ENGINE_RENDERER_CAMERACONTROLLER_H_

#include "Core/Core.h"
#include "Camera.h"
#include "OrthoGraphicCamera.h"
#include "PerspectiveCamera.h"

#include 
#include 

#include 

namespace cheetah
{
    class CH_API CameraController
    {
    public:
        CameraController(const OrthoGraphicCameraParams& params);
        CameraController(const PerspectiveCameraParams& params);

        // affect ProjectionMatrix
        void setZoom(const float& zoom);
        void setAspectRatio(const float& width, const float& height);

        // affect ViewMatrix
        void setPosition(const glm::vec3& position);
        void translate(const glm::vec3& position);
        void rotate(const float& degrees, const glm::vec3& axis);

        inline float getZoom() const { return m_camera->getZoom(); };
        inline float getAspectRatio() const { return m_camera->getAspectRatio(); };
        inline glm::vec3 getPosition() const { return m_position; };
        inline glm::vec3 getRotationAxis() const { return m_rotationAxis; };
        inline float getRotationDegrees() const { return m_rotationDegrees; };
        inline Camera& getCamera() const { return *m_camera; };
    private:
        float m_rotationDegrees;
        glm::vec3 m_rotationAxis;
        glm::vec3 m_position;
        std::unique_ptr m_camera;
    };
}

#endif // !CHEETAH_ENGINE_RENDERER_CAMERACONTROLLER_H_
// CameraController.cpp
#include "CameraController.h"

namespace cheetah
{
    CameraController::CameraController(const OrthoGraphicCameraParams& params)
        :
        m_camera(std::make_unique(params)),
        m_position(params.position),
        m_rotationAxis(params.rotationAxis),
        m_rotationDegrees(params.rotationDegrees)
    {
    }

    CameraController::CameraController(const PerspectiveCameraParams& params)
        :
        m_camera(std::make_unique(params)),
        m_position(params.position),
        m_rotationAxis(params.rotationAxis),
        m_rotationDegrees(params.rotationDegrees)
    {
    }

    void CameraController::setZoom(const float& zoom)
    {
        m_camera->setZoom(zoom);
    }

    void CameraController::setAspectRatio(const float& width, const float& height)
    {
        m_camera->setAspectRatio(width / height);
    }

    void CameraController::setPosition(const glm::vec3& position)
    {
        m_position = position;
        m_camera->setViewMatrix(glm::rotate(glm::translate(glm::mat4(1.0f), position), m_rotationDegrees, m_rotationAxis));
    }

    void CameraController::translate(const glm::vec3& position)
    {
        m_position = position;
        m_camera->setViewMatrix(glm::translate(m_camera->getViewMatrix(), m_position));
    }

    void CameraController::rotate(const float& degrees, const glm::vec3& axis)
    {
        m_rotationDegrees = degrees;
        m_rotationAxis = axis;
        m_camera->setViewMatrix(glm::rotate(m_camera->getViewMatrix(), degrees, axis));
    }
}

implementation
Here is a possible way to implement the CameraController

// MainCamera.h
#ifndef GAME_MAINCAMERA_H_
#define GAME_MAINCAMERA_H_

#include "Cheetah.h"

class MainCamera : public cheetah::CameraController
{
public:
    MainCamera(const cheetah::PerspectiveCameraParams& params);
    void onUpdate(const float& deltaTime);
    bool onWindowResize(const cheetah::WindowResizeEvent& event);
private:
    void handleKeyInput(const float& deltaTime);
};

#endif // !GAME_MAINCAMERA_H_

// MainCamera.cpp
#include "MainCamera.h"

using namespace cheetah;
using namespace math;
using namespace input;

MainCamera::MainCamera(const cheetah::PerspectiveCameraParams& params)
    : CameraController(params)
{
}

bool MainCamera::onWindowResize(const WindowResizeEvent& event)
{
    setAspectRatio((float)event.m_width, (float)event.m_height);
    return true;
}

void MainCamera::onUpdate(const float& deltaTime)
{
    handleKeyInput(deltaTime);
}

void MainCamera::handleKeyInput(const float& deltaTime)
{
    // reset
    if (Input::isKeyPressed(keys::R))
    {
        setPosition(vec3(0.0f, 0.0f, 0.0));
    }

    // moving
    if (Input::isKeyPressed(keys::W))
    {
        translate(vec3(0.0f, -(0.001f * deltaTime), 0.0f));
    }
    if (Input::isKeyPressed(keys::A))
    {
        translate(vec3(-(0.001f * deltaTime), 0.0f, 0.0f));
    }
    if (Input::isKeyPressed(keys::S))
    {
        translate(vec3(0.0f, 0.001f * deltaTime, 0.0f));
    }
    if (Input::isKeyPressed(keys::D))
    {
        translate(vec3(0.001f * deltaTime, 0.0f, 0.0f));
    }

    // rotating
    if (Input::isKeyPressed(keys::Q))
    {
        rotate(-(0.001f * deltaTime), vec3(0, 1, 0));
    }
    if (Input::isKeyPressed(keys::E))
    {
        rotate(0.001f * deltaTime, vec3(0, 1, 0));
    }
    if (Input::isKeyPressed(keys::Z))
    {
        translate(vec3(0.0f, 0.0f, 0.001f * deltaTime));
    }
    if (Input::isKeyPressed(keys::X))
    {
        translate(vec3(0.0f, 0.0f, -(0.001f * deltaTime)));
    }
}

Device Recommendation – Which Medium Format Film Camera Should an SLR Type Watch?

The Mamiya RB67 is a very good candidate for what you need.

The 6×7 is "almost" 6×6, you have the flexibility to crop.

Make sure you get a good back, preferably a Pro-SD. I had 2 Pro's backs (ugly condition) and one of them has strange light leaks that I still couldn't fix with seals. I just got a new 120 Pro SD back and it should make me happy.

The cost of the film is nothing compared to the pleasure you get by taking the time to compose and shoot. Digital takes away the fun of "slowness".

Enjoy and report back what you chose and how you like it.

Cleaning – How can I remove a piece of dirt from the lens system of a compact camera?

background

I have a Panasonic Lumix compact camera that caught some dirt between the lenses or the sensor out of nowhere.
I made sure it wasn't on the outside of the lens.
When zooming (optically), neither size nor position changed, but at best became more or less diffuse (but never sharp).
This is what the lower left quarter of a photo looked like:

lower left quarter of a photo

I tried to subject the camera to moderate forces (shaking, rotating) at different lens positions (i.e. optical zoom levels), but the particle didn't move at all.
I have not opened the camera.

Then when I tried to take another picture to show you the effect, the thing was gone as suddenly as it came.
Of course, I made something I do make it move, but I have no idea what.

Years later it happened again. This is the bottom right side of a photo with a white background:

lower right quarter of a photo

Current question

Happiness solved my problem, but I wonder what targeted efforts I could have made. Therefore I ask: If a piece of dirt gets stuck somewhere in the beam path of a compact camera, what possible measures can remove it? I am only interested in solutions in which the device is not disassembled.

Color – why not use a camera as a colorimeter?

Camera Colorimeter is an app on Google Play that uses your phone's camera as a colorimeter to calibrate other devices.

https://play.google.com/store/apps/details?id=com.auralisoft.colorimeter

(Some experimental results)

I get very consistent shooting results with the back camera of a Nexus 6.
Here are 10 captured RGB values ​​from the same (pretty cool) white screen on a Nexus 7 2013 device and their standard deviations:

       R             G           B
  0.64074441    0.82363862  0.960373769
  0.637419746   0.823843618 0.960422471
  0.635585636   0.823491139 0.961107378
  0.637959867   0.823703707 0.960575674
  0.637286725   0.823480298 0.960555295
  0.636529085   0.826055671 0.963249426
  0.637193203   0.822952933 0.961079831
  0.635713642   0.824445067 0.962552416
  0.637704785   0.82248129  0.961555964
  0.635952103   0.82470173  0.962591767
  -------------------------------------

Mean 0.63720892 0.823879407 0.961406399

Stdev 0.00142383 0.00094581 0.000989068

I have no other Nexus 6 to try and another Nexus 7 device undoubtedly gives slightly different (but self-consistent) results. We are not interested in how the photos look or how noisy they are, but in whether we can get a good RGB value that is averaged over many pixels. Since camera phones have electronic locks, there is no consistency problem with mechanical locks in SLR cameras discussed by other posters here.

(Actual results)

Here are some results before and after calibration.

I used a Nexus 6's camera to calibrate an Xperia C4 phone, and then measured the Xperia's display before and after calibration with a Datacolor Spyder 4 colorimeter.

The only calibration that was carried out on the camera of the Nexus 6 was to give it a reference white point D65 using the "Capture white point" menu option in the Camera Colorimeter app. The reference D65 white point came from another display that was calibrated with the Spyder 4 colorimeter.

First of all, the non-calibrated gamma curve of the Xperia C4 (yellow):

Uncalibrated gamma

The cyan line is the average gamma. The white curve is the target sRGB gamma. The Xperia C4's uncalibrated gamma is too low and deviates significantly from the sRGB target.

Here is the Xperia C4's gamma curve after calibration that follows the target sRGB curve much more closely:

Gamma after calibration

Next is a graphical comparison between DeltaE (2000) errors for different grayscale before and after calibration. The average DeltaE error dropped from 3.06 to 142 after calibration.

Grayscale deltaE before and after calibration

Here are CIE diagrams showing the color gamut (white triangle) and saturation runs (small solid circles) before and after calibration. The black triangle is the target sRGB area. The small squares are the saturation targets.

Before calibration:
CIE diagram (not calibrated)

After calibration:
CIE diagram (calibrated)

Finally, the following diagram compares the average DeltaE errors before and after calibration to the saturation points of individual primary and secondary colors and the average overall DeltaE errors across all colors:

Saturation sweeps error comparison

The average overall DeltaE error fell from 3.69 to 2.30.

Set the webcam camera for cheese using the command line

I have cheese (3.18.1) on Ubuntu 16.04 LTS. When I run it, however, there are no settings.

Theoretically, the camera can be set via the settings as described here:

Where are the settings / settings in Cheese Photo Booth?

Sometimes (like in my situation) the settings menu doesn't open. There is a workaround, but it is not ideal:

Gnome Cheese Settings / Prefs menu is missing

What about starting cheese from the command line? Does anyone have an example of device selection? I've tried the device number (from lsusb) and name, but all I get is a segmentation error, so I'm probably doing something wrong. For example:

Cheese – device "USB camera"

Any thoughts? Yes, there is guvcview, but cheese is installed by default in many systems, and I would imagine that it would be useful to know this type of camera specification.

Thank you very much.

Camera – FUJIFILM X-T4 live stream functions

I'm trying to figure out how useful FUJIFILM X-T4 will be as a streaming device.

According to the specifications, it is capable of recording decent DCI4K 60 fps 10 bits.

It can also output it properly through the HDMI interface.

It has a USB connection through which the video can be technically transmitted while it functions as a UVC (e.g. Look Sigma fp).
Instead, only tethering mode appears to be available (either via USB or WiFi). I found out that it could be the PTP protocol.

So here are my questions:
What is "thethering mode"? What are the PTP image properties?

Please correct the tags, I couldn't find the right ones
Also asked there: https://video.stackexchange.com/questions/29795/fujifilm-x-t4-live-stream-capabilites

Unit – How is the main camera cached as a global variable?

I want to create a utility class that, among other things, returns a cached reference to the main camera. Is the following code correct? I'm worried that I'm doing it wrong and that FindGameObjectWithTag is called every time the getter is referenced.

using UnityEngine;

public static class Utils
{
    public static Camera MainCamera { get; } = Camera.main;

}

Computer Vision – Use a rotation matrix to transform / move a pinhole camera

I have a pinhole camera model with the following extrinsic (in the earth-centered, earth-fixed coordinate system (ECEF)) and intrinsic parameters.

Focal length (x, y) = 55000 px, optical center = (2400.540)

Camera center (x, y, z), (ground coordinates) = -2322996.2171387854 -3875494.0767072071 5183320.6008059494 (ECEF)

Rotation matrix (3 × 3, camera floor frame) = ((0.88982706839551795, -0.45517069374030594, 0.032053516353234932), (-0.44472722029994571, -0.84940151315102252, 0.284138643941715677)

I have to move the camera so that it points to the correct position on the floor based on an ECEF transformation matrix (4×4). It looks like this:

((0.99999922456661872, 0.00043965959331068635, -0.0011651461883787318, 7033.5303197340108),
(-0.00044011741039666426, 0.99999982604190574, -0.00039269946235032278, 814.02427618065849),
(0.0011649733316053631, 0.00039321195895935108, 0.99999924411047925, 4139.9400998316705), (0, 0, 0, 1))

The 3 × 3 matrix section formed by the first three rows and columns is the rotation component, the first three values ​​in the last column are the translation component. My general understanding is that I have to add the translation component to the coordinates of the center of the camera while multiplying the camera by the rotation component to the ground rotation matrix. Is that enough or should I do something extra?

Disable camera drivers

I have two cameras on my rooted Android 9 device (Sony Xperia X F5122). A camera is defective (in terms of hardware). Now I want to disable it completely without recompiling my Android ROM and without using an app that "blocks access". For example, change a driver setting or similar.