Hazel game engine (033) orthographic camera implementation

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

Camera implementation principle BLOG: https://blog.csdn.net/qq_34060370/article/details/129391683

foreword

  • The two programs

    In order to implement a simple orthographic camera that can watch objects in the scene

  • Camera related concepts

    • camera definition

      It provides us with a way to observe the world. The camera observes all objects in the scene from a specific angle. Not only does it have a specific angle, but it can also adjust the field of view to observe the scene.

    • camera concept

      The camera does not exist, but the projection and observation matrix coordinate space of the abstract camera is calculated , and the objects in the scene are first transformed into the observation matrix, and finally transformed into the projection matrix coordinate space.

    • camera properties

      Fov field of view size, own position, aspect ratio, range of near and far planes, etc.

    • Camera observation matrix derivation

      • Introduce working methods

        When the camera moves backwards, the objects in the scene actually move forward

        The camera rotates to the right, in fact, the objects in the scene rotate to the left

      • How the camera observation matrix is ​​calculated

        The transformation matrix transform composed of the position of the camera and the rotation angle is inverse , and the matrix view is the observation matrix, and the object in the scene is transformed into this coordinate space by multiplying the observation matrix by this observation matrix .

        Inversion is a method of calculating the observation matrix, and the second method is to use Euler angles + LookAt to calculate the observation matrix (this is the blog linked at the beginning of the article)

    • official

      • OpenGL

        • Write code sequence: project * view * world * verpos

          After the camera moves, it is best to calculate the latest camera's proj*view matrix on the CPU and then pass it to GLSL

          Because if the proj and view are transferred to the GPU, each object has to be multiplied by the proj*view matrix, which can be placed on the CPU so that it only needs to be done once + uploaded.

        • Reading order: from right to left

      • Directx

        • Write code sequence: verpos * world * view * project
  • API design

    Renderer::BeginScene(camera);
    Renderer::Submit(m_Shader1, VertexArray1);// 给场景提交要渲染的物体
    Renderer::Submit(m_Shader2, VertexArray2);// 给场景提交要渲染的物体
    Renderer::EndScene();
    Renderer::Flush();
    void BeingScene(Camera& camera){
          
          
        // 在cpp中计算Project * view矩阵,并存储起来,
        this->ViewProjectionMatrix =  camera.getProjectionMatrix() * camera.getViewMatrix();
    }
    void Submit(Shader& shader, VertexArray& v){
          
          
        shader->Bind();						// 着色器绑定
        glUniformvec4("viewprojection", this->ViewProjectionMatrix);// 上传给Uniform
        v->bind();	// 绑定顶点数组
        RenderCommand::DrawIndexed(vertexArray);// drawcall
    }
    
  • This section completes the class diagram

    Please add a picture description

Record thinking points

key code

// 投影矩阵计算
OrthographicCamera::OrthographicCamera(float left, float right, float bottom, float top)
    : m_ProjectionMatrix(glm::ortho(left, right, bottom, top, -1.0f, 1.0f)), m_ViewMatrix(1.0f){
    
    
        m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
    }
// 投影观察矩阵
void OrthographicCamera::RecalculateViewMatrix(){
    
    
    glm::mat4 transform = glm::translate(glm::mat4(1.0f), m_Position) *
    glm::rotate(glm::mat4(1.0f), glm::radians(m_Rotation), glm::vec3(0, 0, 1)); // 绕z轴旋转
	
    m_ViewMatrix = glm::inverse(transform);
    // 投影观察矩阵
    m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}
// 物体上传场景
void Renderer::Submit(const std::shared_ptr<Shader>& shader, const std::shared_ptr<VertexArray>& vertexArray){
    
    
    shader->Bind();// 着色器邦迪
    shader->UploadUniformMat4("u_ViewProjection", m_SceneData->ViewProjectionMatrix);// 上传到Uniform

    vertexArray->Bind();// 顶点数组绑定
    RenderCommand::DrawIndexed(vertexArray);// drawcall
}
void Shader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix){
    
    
    GLint location = glGetUniformLocation(m_RendererID, name.c_str());// 获取uniform名称的位置
    glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));// 根据位置上传
}
// glsl
uniform mat4 u_ViewProjection;// 声明uniform
void main(){
    
    
    v_Position = a_Position;
    v_Color = a_Color;
    gl_Position = vec4(a_Position, 1.0);	
    // 将顶点变换到投影矩阵坐标空间(裁剪空间)下:projection * view * world * vpos
    gl_Position = u_ViewProjection * vec4(a_Position, 1.0);	
}

About Window Scale Affecting Graphics Display

OrthographicCamera::OrthographicCamera(float left, float right, float bottom, float top)
    : m_ProjectionMatrix(glm::ortho(left, right, bottom, top, -1.0f, 1.0f)), m_ViewMatrix(1.0f){
    
    
    m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}

Pre-points

  • The contrast between the top, bottom, left and right of the window is 1 and becomes 2

    If the visible window is from 1 to 2, the range surrounded by the triangle 0.5 will shrink , so the graph will become smaller.

    glm::ortho(-2, 2, -2, 2, -1.0f, 1.0f) gives a matrix value of

    0.5 0	0	0
    0 	0.5 0	0
    0	0	-1	0
    0	0 	0	1
    
  • Minified result

    Please add a picture description

Specific issues

  • square to rectangle

    The window is 1280 * 720. When glm::ortho(-1.0f,1.0f, -1.0f, 1.0f, -1.0f, 1.0f);, the original square blue quad becomes a rectangle

    Please add a picture description

  • fix back to square

    Under 1280*720, the left right needs to be passed in about 1280/720=1.7, and the width is enlarged, so that the left and right viewing angles become larger , and the wide range surrounded by objects shrinks , so that it becomes a square.

    /*
    由于窗口的大小是1280 :720,是16 / 9 = 1.77777
    那么设置m_Camera的宽设置 1.6范围,高设为0.9就可以解决。或者 1.7与1也行
    */
    Application::Application()
        :m_Camera(-1.6f, 1.6f, -0.9f, 0.9f){
          
          }
    

    Please add a picture description

GLM library function related

  • glm:: ortho

    left = -1.0f;right = 1.0f;bottom = -1.0f;top = 1.0f
    glm::ortho(left,right, bottom, top, -1.0f, 1.0f);

    The resulting matrix is

    1 0  0 0
    0 1  0 0
    0 0 -1 0
    0 0  0 1
    
  • glm::translate(glm::mat4(1.0f), m_Position);

    m_Position= {0.5f, 0.5f, 0.5f};

    glm::mat4(1.0f), is a 4x4 identity matrix

    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
    

    glm::translate(glm::mat4(1.0f), m_Position);

    /*
        glm::translate函数中
        mat<4, 4, T, Q> Result(m); 
        Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
        Result[3]是第4行,m[0]是第1行,m[1]是第2行,m[2]是第3行。。。
        第四行  = (1 * 0.5,0,0,0) + (0, 1 * 0.5, 0, 0) + (0, 0, 1 * 0.5, 0) + (0, 0, 0, 1)
    */
    // 最后的结果是// 有可能反了:第四行应该与第四列交换
    1 	0 	0 	0
    0 	1 	0 	0
    0 	0 	1 	0
    0.5 0.5 0.5 1
    

all codes

  • OrthographicCamera

    class OrthographicCamera{
          
          
    public:
        OrthographicCamera(float left, float right, float bottom, float top);
        const glm::vec3& GetPosition() const {
          
           return m_Position; }
        void SetPosition(const glm::vec3& position) {
          
           m_Position = position; RecalculateViewMatrix(); }
        float GetRotation() const {
          
           return m_Rotation; }
        void SetRotation(float rotation) {
          
           m_Rotation = rotation; RecalculateViewMatrix(); }
        const glm::mat4& GetProjectionMatrix() const {
          
           return m_ProjectionMatrix; }
        const glm::mat4& GetViewMatrix() const {
          
           return m_ViewMatrix; }
        const glm::mat4& GetViewProjectionMatrix() const {
          
           return m_ViewProjectionMatrix; }
    private:
        void RecalculateViewMatrix();
     private:
        glm::mat4 m_ProjectionMatrix;
        glm::mat4 m_ViewMatrix;
        glm::mat4 m_ViewProjectionMatrix;
        glm::vec3 m_Position = {
          
           0.0f, 0.0f, 0.0f };// 位置
        float m_Rotation = 0.0f;					// 绕z轴的旋转角度
    };
    
    // 初始化用glm计算正交投影矩阵
    OrthographicCamera::OrthographicCamera(float left, float right, float bottom, float top)
        : m_ProjectionMatrix(glm::ortho(left, right, bottom, top, -1.0f, 1.0f)), m_ViewMatrix(1.0f)
        {
          
          
            m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
        }
    // 投影观察矩阵计算
    void OrthographicCamera::RecalculateViewMatrix()
    {
          
          
        // 观察矩阵
        glm::mat4 transform = glm::translate(glm::mat4(1.0f), m_Position) *
            glm::rotate(glm::mat4(1.0f), glm::radians(m_Rotation), glm::vec3(0, 0, 1));
    
        m_ViewMatrix = glm::inverse(transform);
        m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
    }
    
  • Renderer

    class Renderer{
          
          
    public:
        static void BeginScene(OrthographicCamera& camera);	// 开始场景
        static void EndScene();		// 结束场景
        static void Submit(const std::shared_ptr<Shader>& shader, const std::shared_ptr<VertexArray>& vertexArray);// 提交物体的顶点数组
        inline static RendererAPI::API GetAPI() {
          
           return RendererAPI::GetAPI(); }
    private:
        struct SceneData {
          
          
            glm::mat4 ViewProjectionMatrix;
        };
        static SceneData* m_SceneData;
    };
    
    Renderer::SceneData* Renderer::m_SceneData = new Renderer::SceneData;
    void Renderer::BeginScene(OrthographicCamera& camera){
          
          
        m_SceneData->ViewProjectionMatrix = camera.GetViewProjectionMatrix(); // 保存计算的Projection * view矩阵
    }
    void Renderer::EndScene(){
          
          }
    void Renderer::Submit(const std::shared_ptr<Shader>& shader, const std::shared_ptr<VertexArray>& vertexArray){
          
          
        shader->Bind();			// 着色器绑定
        shader->UploadUniformMat4("u_ViewProjection", m_SceneData->ViewProjectionMatrix);// 上传投影观察矩阵
    
        vertexArray->Bind();// 顶点数组绑定
        RenderCommand::DrawIndexed(vertexArray);// drawcall
    }
    
  • Shader

    void UploadUniformMat4(const std::string& name, const glm::mat4& matrix);
    void Shader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix){
          
          
        GLint location = glGetUniformLocation(m_RendererID, name.c_str());
        glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
    }
    
  • Application

    	OrthographicCamera m_Camera;
    private:
    	static Application* s_Instance;
    
    Application::Application() : m_Camera(-1.6f, 1.6f, -0.9f, 0.9f){
          
          
        // 着色器代码
        std::string vertexSrc = R"(
    			#version 330 core
    
    			layout(location = 0) in vec3 a_Position;
    			layout(location = 1) in vec4 a_Color;
    			uniform mat4 u_ViewProjection;
    			out vec3 v_Position;
    			out vec4 v_Color;
    			void main()
    			{
    				v_Position = a_Position;
    				v_Color = a_Color;
    				gl_Position = u_ViewProjection * vec4(a_Position, 1.0);	
    			}
    		)";
    void Application::Run(){
          
          
        while (m_Running){
          
          
            RenderCommand::SetClearColor({
          
           0.1f, 0.1f, 0.1f, 1 });
            RenderCommand::Clear();
    		/*
    			5和6指明近和远平面范围
    			glm::ortho(left, right, bottom, top, -1.0f, 1.0f)
    			摄像机位置的z轴位置只要-1~1之间就行
    		*/
            m_Camera.SetPosition({
          
           0.5f, 0.5f, 0.0f });
            m_Camera.SetRotation(45.0f);
    
            Renderer::BeginScene(m_Camera);
            // 绘制四边形
            Renderer::Submit(m_BlueShader, m_SquareVA);
    
            // 绘制三角形
            Renderer::Submit(m_Shader, m_VertexArray);
    
            Renderer::EndScene();
    

Guess you like

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