OpenGL的矩阵操作
- 旋转
- 平移
- 缩放
- 压栈/出栈
单位向量-X轴-(1,0,0)
单位矩阵-X,Y,Z 三轴-(1,0,0,0,1,0,0,0,1)
相关库
GLTools中有一个组件叫做Math3d,其中包含了大量好用的OpenGL一致的3D数学和数据类型.
Math3d库 ,有两个数据类型,能够表示一个三维或者思维向量,M3DVector3f
可以表示一个三维向量(x,y,z),而M3DVector4f
可以表示一个思维的向量(x,y,z,w)--W表示缩放因子,在典型的情况下W的坐标设为1.0, xyz值除w,进行缩放,而除以1.0本质上不改变xyz值.
typedef float M3DVector3f[3];
typedef float M3DVector4f[4];
//声明一个3分量向量操作:
M3DVector3f vVector3;
//声明一个4分量向量操作:
M3DVector4f vVector4 = {0.0f,0.0f,1.0f,1.0f};
//声明一个3分量顶点数组:
M3DVector3f vVerts[] = { -0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,0.5f,0.0f
}
向量/矩阵 的 点乘

//实现点乘的方法
//方法1:返回值为-1到1区间的值,它代表两个向量的余弦值.
//余弦值:直角三角形中,锐角的 邻边值/斜边值 = 余弦值;
float m3dDotProduct3(const M3DVector3f u,const M3DVector3f v);
//方法2:返回两个向量之间的弧度.
float m3dGetAngleBetweenVetor3(const M3DVector3f u,const M3DVector3f v);
向量/矩阵 的 叉乘

// result 是结果, 就是上图的V3 ,它是一个向量值
void m3dCrossProduct3(const M3DVector3f result,
const M3DVector3f u,
const M3DVector3f v);
//v3是一个垂直于,V1/V2所在面的向量.
//注意,叉乘不满足交换律,
a*b != b*a;
OpenGL下的矩阵

实现平移/旋转/缩放 叉乘
GLfloat xPos = 0.0f;//x轴平移量
GLfloat yPos = 0.0f;//y轴平移量
GLfloat zRot = 0;//旋转角度 - 需要抓换成弧度才能用于求矩阵
GLfloat xScale = 1;//x轴缩放量 缩放的计算方式是,原边长*缩放因子的绝对值
GLfloat yScale = 1;//y轴缩放量
void SpecialKeys(int key ,int x, int y){
GLfloat stepSize = 0.025;
if (key == GLUT_KEY_UP) {
yPos += stepSize;
zRot += 10.0;
yScale += 0.1;
xScale += 0.1;
}
if (key == GLUT_KEY_DOWN) {
yPos -= stepSize;
zRot -= 10.0;
yScale -= 0.1;
xScale -= 0.1;
}
if (key == GLUT_KEY_LEFT) {
xPos -= stepSize;
zRot -= 10.0;
xScale -= 0.1;
yScale -= 0.1;
}
if (key == GLUT_KEY_RIGHT) {
xPos += stepSize;
zRot += 10.0;
xScale += 0.1;
yScale += 0.1;
}
//检测边沿碰撞
if (blockSize+xPos > 1) xPos = 1-blockSize;
if (-blockSize + xPos < -1) xPos = blockSize - 1;
if (blockSize + yPos > 1) yPos = 1-blockSize;
if (-blockSize + yPos < -1) yPos = blockSize - 1;
glutPostRedisplay();
}
/// 开始渲染
void RenderScence(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat redColor[] = { 1.0,0.0,0.0,1.0f};
//定义矩阵
M3DMatrix44f mFinalTranslation , mTranslationMatrix , mRotationMartix ,mScaleMartix;
//计算平移矩阵
m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0);
//计算旋转矩阵
m3dRotationMatrix44(mRotationMartix, m3dDegToRad(zRot),0.0, 0.0, 1.0);
//计算缩放矩阵
m3dScaleMatrix44(mScaleMartix, xScale, yScale, 0);
// 平移 & 旋转 矩阵叉乘
m3dMatrixMultiply44(mFinalTranslation, mTranslationMatrix, mRotationMartix);
// 平移旋转后再缩放
m3dMatrixMultiply44(mFinalTranslation, mFinalTranslation, mScaleMartix);
// shaderManager.UseStockShader(GLT_SHADER_FLAT,mTranslationMatrix,redColor);//平移
// shaderManager.UseStockShader(GLT_SHADER_FLAT,mRotationMartix,redColor);//旋转
// shaderManager.UseStockShader(GLT_SHADER_FLAT,mScaleMartix,redColor);//缩放
shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTranslation,redColor); //叉乘方式
squareBatch.Draw();
glutSwapBuffers();
}

矩阵堆栈的压栈/出栈
//模型视图矩阵的压栈 modelViewMatrix属于GLMatrixStack 类型
//写法1;
modelViewMatrix.PushMatrix(); //模型视图矩阵堆栈进行压栈;
M3DMatrix44f mCameraFrame;
cameraFrame.GetCameraMatrix(mCameraFrame);
modelViewMatrix.MultMatrix(mCameraFrame); //栈顶矩阵叉乘
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame); //栈顶矩阵叉乘
//上面的代码中, cameraFrame & objectFrame 是提前声明的两个坐标矩阵
//观察者位置
//GLFrame cameraFrame;
//世界坐标位置
//GLFrame objectFrame;
//inline void PushMatrix(void) {
// if(stackPointer < stackDepth) {
// stackPointer++;
// m3dCopyMatrix44(pStack[stackPointer], pStack[stackPointer-1]);
// }
// else
// lastError = GLT_STACK_OVERFLOW;
// }
//我们看看当模型视图矩阵堆栈调用 .PushMatrix(void) 方法的时候的源码,
//压栈的时候是把栈顶的数据copy了一份然后插入到堆栈的栈顶处;
//写法2-> 在SetupRC的时候,直接让物体坐标系向观察者坐标系移动
//在 void SetupRC() {} 中 , 代码 -> cameraFrame.MoveForward(-15.0f); --> objectFrame.MoveForward(15.0f);
//然后在压栈的时候,就可以直接Push(objectFrame)
//4. pop push与pop是成对出现的
modelViewMatrix.PopMatrix();
//5. 交换缓存
glutSwapBuffers();
压栈&出栈流程图

网友评论