1. 视觉坐标
视觉可以理解为屏幕坐标。是一个虚拟的固定的坐标系。
2. 视图变换
视图变化是当观察者移动位置时视图相应的发生角度的变换,默认观察者是以z轴负方向观察,当观察沿x轴负方向观察时,实际观察模型的侧面。
一般都是先进行视觉变化,已确定观察的视角,然后进行其它变化。这样更容易理解变化的过程。
3. 模型变换
是用于操纵模型或某一对象,通过变换改变了其位置,大小或者角度。
4. 模型视图的二次元
模型视图二次元是模型视图两种变换在线性变换管线中的进行组合,成为一个单独的变化矩阵。即模型视图矩阵。
5. 投影变换
将模型视图变换之后应用到顶点上,这种变换后实际上是确认了视景体和剪裁平面。
对于平行投影来说,视景体是一个四边平行于投影方向,长度无限的四棱柱;
对于透视投影来说,则是以投影中心为顶点的四棱锥。
6. 视口变换
当以上变换结束后,我们得到了一个场景的二维投影,这时候我们需要将其映射到窗口的某片区域进行显示,还包括颜色缓冲区与窗口像素间的转换。
7. 模型视图矩阵
模型视图矩阵是一个4x4的矩阵,所表示一个变换后的坐标系,模型视图变换就是通过将要变换的顶点和模型变换矩阵相乘得到一个变换后相对于视觉坐标系新的坐标系。
下面是一个模型视图变换的例子
GLBatch squareBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.1;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,//一个3x4矩阵忽略了w缩放值
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f};
GLfloat xPos = 0.0;
GLfloat yPos = 0.0;
void SetupRC()
{
//设置背景色
glClearColor(0.0f, 0.0f, 1.0f, 1.0f );
//初始化存储着色器
shaderManager.InitializeStockShaders();
//设置着色器的图片类型和定点数
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
//存储管理顶点着色器的坐标
squareBatch.CopyVertexData3f(vVerts);
//当前管理容器结束标识
squareBatch.End();
}
// 通过键盘的上下左右改变 xPos,yPos的值
void SpecialKeys(int key, int x, int y)
{
GLfloat stepSize = 0.025;
if (key == GLUT_KEY_UP){
yPos += stepSize;
}
if (key == GLUT_KEY_DOWN){
yPos -= stepSize;
}
if (key == GLUT_KEY_LEFT){
xPos -= stepSize;
}
if(key == GLUT_KEY_RIGHT){
xPos += stepSize;
}
if(xPos < (-1.0f + blockSize)){
xPos = -1.0f + blockSize;
}
if(xPos > (1.0f - blockSize)){
xPos = 1.0f - blockSize;
}
if(yPos < (-1.0f + blockSize)){
yPos = -1.0f + blockSize;
}
if(yPos > (1.0f - blockSize)) {
yPos = 1.0f - blockSize;
}
glutPostRedisplay();
}
void RenderScene(void)
{
//清理缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//颜色矩阵
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
//4x4矩阵
M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;
//平移矩阵,平移后后相对于视觉系新的坐标集合会存储在mTranslationMatrix中
//原理是坐标系的每个顶点坐标与平移矩阵进行相乘会得到一个相对与视觉系的新的顶点,所有坐标相乘后就会得到一个相对于视觉的新的坐标系。
//例如将顶点(1,1,1)沿着x正方向移动到(2,1,1)乘以 1,0,0,1即可
// 0,1,0,0
// 0,0,1,0
// 0,0,0,1
m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0.0f);
static float yRot = 0.0f;
yRot += 5.0f;
// 旋转矩阵 转换后相对于视觉系新的坐标集合会存储在mRotationMatrix中
// 其中yRot为旋转的角度,0.0f, 0.0f, 1.0f为旋转的方向;
// 这里是沿着z轴旋转乘以 cos角,-sin角,0,1即可
// sin角, cos角,0,0
// 0, 0, 1,0
// 0, 0, 0,1
m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
// 最终会把平移和旋转的结果应用到mFinalTransform中
m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);
// 通过平面着色器将3d坐标转换成2d坐标
shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vRed);
// 绘制
squareBatch.Draw();
// 后台缓冲区和前台缓冲区切换函数
glutSwapBuffers();
}
void ChangeSize(int w, int h)
{
// 确认视口大小
glViewport(0, 0, w, h);
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("MOVE");
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);//监听键盘按键的回调
SetupRC();
glutMainLoop();
return 0;
}
8. 模型视图投影矩阵
因为计算机只识别单元立方的坐标系,有时候我们需要跳出坐标系进行变换,比如说当我们采用投影变换后得到的非单元立方的坐标系,这时候就要通过模型视图矩阵转型成单位立方矩阵.
下面是一个通过透视投影然后经过模型视图投影矩阵变换的例子
GLFrustum viewFrustum;
GLShaderManager shaderManager;
GLTriangleBatch torusBatch;
void ChangeSize(int w, int h)
{
if(h == 0)
h = 1;
glViewport(0, 0, w, h);
//进行透视投影得到视景图
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 1000.0f);
}
void RenderScene(void)
{
static CStopWatch rotTimer;
//时间监听,得到当前时间
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
//平移变换矩阵, 向z轴平移-2.5f
m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);
//旋转变换矩阵, 沿y轴逆时针旋转
m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
//得到视图模型变换后矩阵
m3dMatrixMultiply44(mModelview, mTranslate, mRotate);
//其实视图变换矩阵就可以绘制显示了,但是计算机只识别单元立方体坐标系,而经过透视投影之后为非单元立方体坐标系,所以需要模型视图投影矩阵进行转换成单元立方坐标系,这里首先先从透镜矩阵实例viewFrustum,取到投影矩阵坐标,然后和模型视图矩阵通过m3dMatrixMultiply44方法转换换成单元立方坐标系放在mModelViewProjection中.
m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(),mModelview);
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
//通过平面存储着色器转换成二维的顶点坐标
shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);
//绘制
torusBatch.Draw();
glutSwapBuffers();
glutPostRedisplay();
}
void SetupRC()
{
glClearColor(0.8f, 0.8f, 0.8f, 1.0f );
//开启深度测试,防止图元重叠
glEnable(GL_DEPTH_TEST);
shaderManager.InitializeStockShaders();
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
//多边形模式,多边形图元以线段的形式前后都显示
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("ModelViewProjection");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}