视图矩阵的推导

简介: 把物体从世界坐标系转化到视点坐标系的矩阵称为视图矩阵。      下面我们先看下OpenGL中视图矩阵的推导过程:      假设视点或camera的局部坐标系为UVN,UVN分别指向右方、上方和后方从而构成右手坐标系,视点则处于局部坐标系的原点位置。

        把物体从世界坐标系转化到视点坐标系的矩阵称为视图矩阵。

     下面我们先看下OpenGL中视图矩阵的推导过程:

     假设视点或camera的局部坐标系为UVN,UVN分别指向右方、上方和后方从而构成右手坐标系,视点则处于局部坐标系的原点位置。

     就如OpenGL中的函数gluLookAt(eyex, eyey, eyez, lookatx, lookaty, lookatz, upx, upy, upz)一样,给定视点、观察点、以及up向量之后,我们就可以求得视图矩阵。

1、首先我们来求得N = eye – lookat,并把N归一化。

2、up和N差积得到U, U= up X N,归一化U。

3、然后N和U差积得到V

假定设定摄像机参数如下:gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

则N=Normalize((0.0,3.0,4.0)-(0.0,0.0,0.0))=Normalize((0.0,3.0,4.0))= (0.0,0.6,0.8)

    U=up X N= (1.0*0.8-0.6*0.0,0.0*0.0-0.0*0.8, 0.0*0.6-0.0*1.0)=(0.8,0.0,0.0), 归一化后为U=(1.0,0.0,0.0)

    V=N X U=(0.0,0.8,-0.6),归一化后为(0.0,0.8,-0.6)

image

image

 

 

      假设视点坐标系初始和世界坐标系重合,它先进行一个旋转变化,然后再进行一个平移,得到现在视点位置和方位。则此时进行的矩阵变化为image,其中T是平移变化,R是旋转变化,因为OpenGL顶点坐标,使用列向量,所以我们使用逆变换。

image

T的逆矩阵为:

image

对gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);  (Tx,Ty,Tz)=(0.0,3.0,4.0)

     当相机变换进行完Inverse Translation这一步之后,相机的原点和世界原点就重合了,也就是处理完了关于平移的变换。

     我们要把一个世界坐标系点K(Kx, Ky, Kz),表示成(U,V,P)坐标系的点(假设此时,已经经过平移操作,摄像机在世界坐标系的原点),则其公式为:

因为(Lx, Ly, Lz)=(Kx,Ky,Kz)*(U,V,P),【因为世界坐标系的三个基乘以(U,V,P),就会把世界坐标系转变到uvp坐标系,所以世界坐标的顶点坐标,乘以这个矩阵,也会转化到uvp坐标系中的顶点坐标】则有

Lx = Kx * Ux + Ky * Uy + Kz * Uz;

Ly = Kx * Vx + Ky * Vy + Kz * Vz;

Lz = Kx * Px + Ky * Py + Kz * Pz

则转化矩阵为:

image

则完整的公式为:image      image

 

则gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);最终视图矩阵是image

你可以用下面的代码来验证它:

#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdlib.h> 
#include <cmath>

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0); //背景黑色 
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0); //画笔白色 

    glLoadIdentity();  //加载单位矩阵 

    gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glutWireCube(1.0f);
    glutSwapBuffers();
}

 

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    GLdouble mv[16] = { 0 }, pv[16] = { 0 };
    glGetDoublev( GL_MODELVIEW_MATRIX, mv );
    printf("view1:%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f,%5.3f, %5.3f\n", mv[0], mv[1], mv[2], mv[3], mv[4], mv[5], mv[6], mv[7], mv[8], mv[9], mv[10], mv[11], mv[12], mv[13], mv[14], mv[15]);
    glGetDoublev(GL_PROJECTION_MATRIX, pv);

}

 


int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}

以上是OpenGL的视图矩阵,对于D3D,由于使用行向量,左乘,以及左手坐标系,所以视图稍有不同,在D3D11教程中,曾加做过推导:

http://www.cnblogs.com/mikewolf2002/archive/2012/03/11/2390669.html

相关文章
QString与char *之间的完美转换,支持含有中文字符的情况
QString与char *之间的完美转换,支持含有中文字符的情况
2818 0
|
缓存 Ubuntu JavaScript
踩坑记录:QML加载图片资源
踩坑记录:QML加载图片资源
2679 0
关于 QGLWidget和QOpengGLWidget透明相关问题 的解决方法
关于 QGLWidget和QOpengGLWidget透明相关问题 的解决方法
关于 QGLWidget和QOpengGLWidget透明相关问题 的解决方法
【Qt 学习笔记】Qt窗口 | 标准对话框 | 颜色对话框QColorDialog
【Qt 学习笔记】Qt窗口 | 标准对话框 | 颜色对话框QColorDialog
3028 3
|
人工智能 自然语言处理 搜索推荐
师资培训|AIGC教学评估体系构建与教学策略优化-某教育科技集团
近日,TsingtaoAI为某教育科技集团交付AIGC赋能教师教学创新课程,本课程围绕国内外最新AIGC技术的发展现状与具体应用场景,深入探讨如何借助智能分析、多模态交互和自动化数据处理,为教学过程“插上”数字化翅膀。课程不仅聚焦于工具与平台的实操演练,还呈现了丰富的本土高校成功案例与落地方法,让参加者充分掌握从课堂管理、作业布置、考试测评到学生个性化指导的全流程智能化改进思路。
774 12
|
存储 人工智能 Java
将 Spring AI 与 LLM 结合使用以生成 Java 测试
AIDocumentLibraryChat 项目通过 GitHub URL 为指定的 Java 类生成测试代码,支持 granite-code 和 deepseek-coder-v2 模型。项目包括控制器、服务和配置,能处理源代码解析、依赖加载及测试代码生成,旨在评估 LLM 对开发测试的支持能力。
651 1
|
编译器 图形学 C++
【计算机图形学】 OpenGL环境配置
【计算机图形学】 OpenGL环境配置
566 0
|
算法 Serverless C++
C++常用头文件概述与示例
C++常用头文件概述与示例
932 0
|
存储 Linux 程序员
Linux进程间通信(IPC)教程 Linux信号量:讲解POSIX信号量在Linux系统进程间通信中的编程实践
Linux进程间通信(IPC)教程 Linux信号量:讲解POSIX信号量在Linux系统进程间通信中的编程实践
635 1
|
边缘计算 算法 计算机视觉
opencv 图像梯度(python)
opencv 图像梯度(python)