Hazel Game Engine (080) Camera System

If there are errors in the code, terminology, etc. in the text, please correct me

foreword

  • The bug in the previous section

    Initialize Entity's m_EntityHandle to null instead of 0

    entt::entity m_EntityHandle{
          
           entt::null };
    operator bool() const {
          
           return m_EntityHandle != entt::null; }
    
  • Contents of this section

    • Design a Camera component

      That is, an entity can use the Camera component

    • This Camera component needs to have a Camera class pointer

      The properties and behaviors of the Camera class

      1. Set to perspective projection projection matrix or orthogonal projection projection matrix (not done)

      2. Whether the main camera

      3. Get the projection projection matrix

      Pay attention to the distinction: Camera component and Camera class, the entity adds the Camera component, the Camera component has the Camera class, so the entity can obtain the Camera through the component

Camera class and Camera component design

  • Newly added Camera.h

    #pragma once
    #include <glm/glm.hpp>
    namespace Hazel {
          
          
    	class Camera {
          
          
    	public:
    		Camera(const glm::mat4& projection)
    			: m_Projection(projection){
          
          }
    		const glm::mat4& GetProjection() const {
          
           return m_Projection; }
    		// TOOD:做透视投影
    	private:
    		glm::mat4 m_Projection;
    	};
    }
    
  • Components.h

    struct CameraComponent {
          
          
        Camera camera;
        bool primary = true;
    
        CameraComponent() = default;
        CameraComponent(const CameraComponent&) = default;
        CameraComponent(const glm::mat4 & projection)
            : camera(projection) {
          
          }
    };
    

Scene switching to the main camera perspective code flow

  • Add an entity to the EditorLayer layer

    EditorLayer.h
    Entity m_CameraEntity;			// 摄像机实体
    
  • The entity adds the camera component and initializes the orthographic projection matrix

    EditorLayer.cpp
    // 初始化摄像机实体
    m_CameraEntity = m_ActiveScene->CreateEntity("Camera Entity");
    m_CameraEntity.AddComponent<CameraComponent>(glm::ortho(-16.0f, 16.0f, -9.0f, 9.0f, -1.0f, 1.0f));
    
  • Find the main camera in the scene onupdate method , and get the transform of the main camera to calculate the view matrix

    Scene.cpp
    void Scene::OnUpdate(Timestep ts)
    {
          
          
        // 获取到主摄像机,并且获取到摄像机的位置,用来计算投影矩阵projection
        Camera* mainCamera = nullptr;
        glm::mat4* cameraTransform = nullptr;
        {
          
          
            auto group = m_Registry.view<TransformComponent, CameraComponent>();
            for (auto entity : group){
          
          
                auto &[transform, camera] = group.get<TransformComponent, CameraComponent>(entity);
    
                if (camera.primary) {
          
          
                    mainCamera = &camera.camera;
                    cameraTransform = &transform.Transform;
                }
            }
        }
        ///
        // 注意这,BeginScene中传入主摄像机的投影矩阵与主摄像机的transform矩阵
        if (mainCamera) {
          
          
            Renderer2D::BeginScene(mainCamera->GetProjection(), *cameraTransform);
            auto group = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
            for (auto entity : group) {
          
          
                auto& [transform, sprite] = group.get<TransformComponent, SpriteRendererComponent>(entity);
                Renderer2D::DrawQuad(transform, sprite.Color);
            }
            Renderer2D::EndScene();
        }
    }
    
  • In the renderer's beginscene method, the projection matrix*view matrix is ​​uploaded to opengl

    Renderer2D.cpp
    void Renderer2D::BeginScene(const Camera& camera, const glm::mat4& transform)
    {
          
          
        // 投影矩阵projection * 视图矩阵
        glm::mat4 viewProj = camera.GetProjection() * glm::inverse(transform);
        s_Data.TextureShader->Bind();		// 绑定shader
        s_Data.TextureShader->SetMat4("u_ViewProjection", viewProj);
    

Two entities, each entity has the effect of the Camera component

  • Entity (camera) 1 is regarded as the main camera

    Please add a picture description

  • Entity (camera) 2 is regarded as the main camera

    Please add a picture description

question

  • Question Details

    Why modifying the fourth column of the transform matrix can change the position of the scene's camera

    /*
    一开始以为:Transform[3]是第四行
    后面查资料才发现Transform[3]应该是第四列
    */ 
    ImGui::DragFloat3("Camera Transform",
    	glm::value_ptr(m_CameraEntity.GetComponent<TransformComponent>().Transform[3]));
    

    The transform matrix is ​​a combination of translation matrix * rotation matrix * scaling matrix, since there is no rotation and scaling matrix set, so

    It can be considered here that the transform matrix is ​​the translate translation matrix

  • translateTranslation Matrix Diagram References

    • The fourth column is the position of the camera

    • The transform matrix is ​​the translate translation matrix

    • The fourth column is represented by Transform[3], so changing Transform[3] can change the position of the camera

  • In addition, some principle reference materials

    1. From subsection 034, the interface of the camera moving to the left actually shows that the object is moving to the right

    2. So changing the fourth column of the camera's transform here doesn't actually change the camera's position

    3. Instead, calculate the camera's view matrix in Renderer2D::BeginScene, multiply it with the projection matrix and upload it to OpenGL

    4. In the OpenGL shader, the projection matrix * view matrix * vertex position of the object is used

      • Transform the vertex position of the object to the observation space through the view matrix

        (The vertex position of the object is transformed to a specific position according to the transform matrix. This section is to translate the vertex to the specified position according to the translate matrix)

        So modifying the value of transform[3] in this section will take effect here

      • Then through the projection matrix transformation to the clipping space , to the standardized device coordinates, to the screen coordinates (displayed on the screen)

    5. On the surface, the camera is moving, but in fact it is the movement of all the vertices that make up the object.

    void Renderer2D::BeginScene(const Camera& camera, const glm::mat4& transform){
          
          
        // 投影矩阵projection * 视图矩阵
        glm::mat4 viewProj = camera.GetProjection() * glm::inverse(transform);
        s_Data.TextureShader->Bind();		// 绑定shader
        s_Data.TextureShader->SetMat4("u_ViewProjection", viewProj);
    

Guess you like

Origin blog.csdn.net/qq_34060370/article/details/132137398