1.OpenGL压栈出栈作用概念
1.压栈出栈操作的是矩阵,一般分为模型视图矩阵和投影矩阵
2.出栈压栈是针对顶点的变化的,为了方便实施,所以用矩阵统一记录且作用在顶点上面
3.压栈出栈一定要成对出现,OpenGL里面模型视图矩阵是全局的,PushMatrix的作用是把当前的栈顶拷贝一份复制在栈顶上,利用这个新的栈顶记录新的变化,绘制新的变化,绘制完毕,PopMatrix是把这个新的栈顶删除掉,栈顶变为记录这次变化之前的栈顶,也就是说通过push和pop达到了既绘制了当前的变化,又没有影响到之前的栈顶状态
// 假设ABC是要作用在需要绘制物体Object上的,Object.Draw()->Object使用Draw()函数绘制完毕,PopMatrix(),恢复之前的栈顶状态
绘制Object的变化,不影响全局的模型视图矩阵
modelViewMatrix.PushMatrix();
模型视图矩阵变化A
模型视图矩阵变化B
模型视图矩阵变化C
Object.Draw();
modelViewMatrix.PopMatrix();
绘制AABBCC的变化,不影响全局的模型视图矩阵
modelViewMatrix.PushMatrix();
模型视图矩阵变化AA
模型视图矩阵变化BB
模型视图矩阵变化CC
AABBCC.Draw();
modelViewMatrix.PopMatrix();
某些变化模型视图矩阵或者投影矩阵要影响全局的那么
模型视图矩阵变化xyz,投影矩阵,影响全局,那么只需要push前面即可,push pop中间的绘制完毕会被清楚掉,如果不在这个范围内就持续影响后续的物体的绘制状态,因为OpenGL状态机是全局的
modelViewMatrix.PushMatrix();
模型视图矩阵变化AAA
模型视图矩阵变化BBA
模型视图矩阵变化CCA
AABBCC.Draw();
modelViewMatrix.PopMatrix();
2.压栈压栈代码实现
//进行调用以绘制场景
void RenderScene(void)
{
//1.颜色值(地板,大球,小球颜色)
static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f};
static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f};
//2.基于时间动画
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
//3.清除颜色缓存区和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//4.加入观察者 平移10步(地板,大球,小球,小小球)
// PushMatrix->1
// cameraFrame是摄像机矩阵,被模型视图矩阵modelViewMatrix作用,第一个PushMatrix前面影响全局
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);
//5.获取光源位置
M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
//6.绘制地面
shaderManager.UseStockShader(GLT_SHADER_FLAT,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor);
// 绘制地面,上面的摄像机矩阵PushMatrix->1是作用在这个上面的,通过模型视图矩阵的变化
floorBatch.Draw();
//大球默认位置(0,0,0)Z深度(3.0) 正负指的是方向, 数字指的移动距离
//7.使得大球位置平移(3.0)向屏幕里面 只移动1次
// 模型视图矩阵发生变化2,作用在后续所有需要绘制的物体上面
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
//8.压栈(复制栈顶)
// PushMatrix->2
// 准备绘制大球,压栈->复制新的栈顶放在原来的栈顶上面
modelViewMatrix.PushMatrix();
//9.大球自转
// 这个模型视图矩阵的变化在PushMatrix->2和PopMatrix->2之间,只对torusBatch的绘制起作用
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
//10.指定合适的着色器(点光源着色器)
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
torusBatch.Draw();
//11.绘制完毕则Pop
// 大球绘制完毕PopMatrix->2
modelViewMatrix.PopMatrix();
//12.画小球
for (int i = 0; i < NUM_SPHERES; i++) {
// PushMatrix->3 绘制若干小球
modelViewMatrix.PushMatrix();
// 是作用在若干小球上的模型视图矩阵modelViewMatrix的变化
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
sphereBatch.Draw();
// PopMatrix->3 若干小球绘制完毕
modelViewMatrix.PopMatrix();
}
//13. 让一个小篮球围绕大球公众自转
//学员提问: 为什么这里老师没有加PushMatrix/PopMatrix ,是可以加的.但是因为是最后的绘图因为没有不会影响就么有添加. 这边给大家添加一组.
// PushMatrix->4 绘制围绕大球公转的一个小球
modelViewMatrix.PushMatrix();
// 公转小球的变化只作用在自身上
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
sphereBatch.Draw();
// PopMatrix->4 绘制完毕
modelViewMatrix.PopMatrix();
// PopMatrix->1 全部结束PopMatrix
modelViewMatrix.PopMatrix();
//14.执行缓存区交换
glutSwapBuffers();
//15
glutPostRedisplay();
}
3.压栈出栈流程提取
// PushMatrix->1
// cameraFrame是摄像机矩阵,被模型视图矩阵modelViewMatrix作用,第一个PushMatrix前面影响全局
modelViewMatrix.PushMatrix(mCamera);
// 模型视图矩阵发生变化2,作用在后续所有需要绘制的物体上面
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
// PushMatrix->2
modelViewMatrix.PushMatrix();
//9.大球自转
// 这个模型视图矩阵的变化在PushMatrix->2和PopMatrix->2之间,只对torusBatch的绘制起作用,大球的变化
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
// 大球绘制完毕PopMatrix->2
modelViewMatrix.PopMatrix();
//12.画小球
for (int i = 0; i < NUM_SPHERES; i++) {
// PushMatrix->3 绘制若干小球
modelViewMatrix.PushMatrix();
// 是作用在若干小球上的模型视图矩阵modelViewMatrix的变化
modelViewMatrix.MultMatrix(spheres[i]);
// PopMatrix->3 若干小球绘制完毕
modelViewMatrix.PopMatrix();
}
// PushMatrix->4 绘制围绕大球公转的一个小球
modelViewMatrix.PushMatrix();
// 公转小球的变化只作用在自身上
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
// PopMatrix->4 绘制完毕
modelViewMatrix.PopMatrix();
// PopMatrix->1 全部结束PopMatrix
modelViewMatrix.PopMatrix();
4.是否一定需要使用矩阵
mv->模型视图矩阵
mvp->模型视图投影矩阵
p->投影矩阵
问题(1): 在绘图时,可以不用矩阵堆栈吗?
答案: 如果绘制比较多,没有push pop是不行的,否则别的变化都作用在mv上了,mv是全局的,本来不是你的也被影响了,push的意思就是,我先占用,等我绘制完了,pop是把我的变化从全局的mv的剔除掉,保持原来的模样,否则就乱套了,push pop就是为了把变化绘制了,还不影响整体环境,如果你不用push或者pop,那你自己精细算mv的数据也是可以的,比如mv+abc-897 绘制,完成绘制之后mv-abc+897,这也可以,但是这只是规则变化,有规律可循,即使你数学非常牛逼,任何一个复杂的图形怎么变化我都能计算出各个顶点的数值,变化完成之后我都可以复原,也可以自己算自己复原,但是,push 和 pop就搞定了,非得自己搞那些事干什么捏
问题(2): MVP矩阵在堆栈中充当什么样角色?
答案: mv只有一个是全局的大家都在用,如果某个图形A,他要有bcdefg变化,那么 push -> mvbcdefg -> pop mv,这时候物体B有一个abc999-366的变化,push -> mv * abc999-366 ->pop ->mv, A和B都是要自己的变化,比如A必须要bcdefg都叉乘了才可作为A的最后的mv渲染,B也是同理,如果不使用push pop,把mvbcdefg abc999-366给B或者A,都是不对的,那就乱套了,不影响全局的变化放在push 和 pop之间,push->占用mv->记录变化->绘制完毕->pop->复原mv
网友评论