一步步学OpenGL二.docx
- 文档编号:8616711
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:53
- 大小:618.94KB
一步步学OpenGL二.docx
《一步步学OpenGL二.docx》由会员分享,可在线阅读,更多相关《一步步学OpenGL二.docx(53页珍藏版)》请在冰豆网上搜索。
一步步学OpenGL二
一步步学OpenGL
(二)
七旋转变换
背景
继上个教程的平移变换之后,这里开始学习旋转变换,也就是能够实现让一个点沿着一个坐标轴旋转一定的角度。
旋转变换将总是改变位置的其中两个坐标,第三个坐标保持不变,这意味着旋转的路径会保持在其中一个平面上:
XY平面(绕Z轴旋转),YZ平面(绕X轴旋转)和XZ平面(绕Y轴旋转)。
也有一些复杂的旋转变换允许图形绕着任意向量旋转,但在我们这个阶段还不需要。
让我们从普遍统一的角度来定义这个问题。
看下面这个图:
我们想从(x1,y1)沿着圆移动到(x2,y2),换句话说就是将点(x1,y1)旋转a2角度。
假设圆的半径是1,那有下面的式子:
我们用下面的三角函数变换公式来推导x2和y2的表达式:
从上面的公式我们可以得到:
再上面的图中我们看的是XY平面,Z轴指向纸面。
X和Y放在4维矩阵里面的的话那么上面的公式可以写成下面的矩阵形式(不影响Z和W分量):
如果我们想实现绕X或Y轴旋转,那么公式基本上是类似的但是变换矩阵的排布略有不同。
下面是绕Y轴旋转的旋转变换矩阵(y不变):
绕X轴旋转的旋转变换矩阵(x不变):
源代码详解
在上个教程的基础上这里代码的变换非常少。
我们只是改变代码中变换矩阵的内容,将平移变换矩阵换成了旋转变换矩阵而已:
World.m[0][0]=cosf(Scale);World.m[0][1]=-sinf(Scale);World.m[0][2]=0.0f;World.m[0][3]=0.0f;
World.m[1][0]=sinf(Scale);World.m[1][1]=cosf(Scale);World.m[1][2]=0.0f;World.m[1][3]=0.0f;
World.m[2][0]=0.0f;World.m[2][1]=0.0f;World.m[2][2]=1.0f;World.m[2][3]=0.0f;
World.m[3][0]=0.0f;World.m[3][1]=0.0f;World.m[3][2]=0.0f;World.m[3][3]=1.0f;
AsyoucanseewerotatearoundtheZaxis.YoucantrytheotherrotationsaswellbutIthinkthatatthispointwithouttrueprojectionfrom3Dto2Dtheotherrotationslookabitodd.Wewillcompletetheminafulltransformationpipelineclassinthecomingtutorials.
这样会看到图形绕着Z轴旋转了。
我们也可以尝试绕其他轴的旋转,但是没有从3d到2d的投影另外两种旋转看上起去会很奇怪,我们会在后面教程中在一个完整的图形变换管线类中来完善它。
示例Demo
#include
#include
#include
#include
#include
#include"ogldev_util.h"
#include"ogldev_math_3d.h"
GLuintVBO;
GLuintgWorldLocation;
constchar*pVSFileName="shader.vs";
constchar*pFSFileName="shader.fs";
staticvoidRenderSceneCB()
{
glClear(GL_COLOR_BUFFER_BIT);
staticfloatScale=0.0f;
Scale+=0.001f;
//旋转变换矩阵
Matrix4fWorld;
World.m[0][0]=cosf(Scale);World.m[0][1]=-sinf(Scale);World.m[0][2]=0.0f;World.m[0][3]=0.0f;
World.m[1][0]=sinf(Scale);World.m[1][1]=cosf(Scale);World.m[1][2]=0.0f;World.m[1][3]=0.0f;
World.m[2][0]=0.0f;World.m[2][1]=0.0f;World.m[2][2]=1.0f;World.m[2][3]=0.0f;
World.m[3][0]=0.0f;World.m[3][1]=0.0f;World.m[3][2]=0.0f;World.m[3][3]=1.0f;
glUniformMatrix4fv(gWorldLocation,1,GL_TRUE,&World.m[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glDrawArrays(GL_TRIANGLES,0,3);
glDisableVertexAttribArray(0);
glutSwapBuffers();
}
staticvoidInitializeGlutCallbacks()
{
glutDisplayFunc(RenderSceneCB);
glutIdleFunc(RenderSceneCB);
}
staticvoidCreateVertexBuffer()
{
Vector3fVertices[3];
Vertices[0]=Vector3f(-1.0f,-1.0f,0.0f);
Vertices[1]=Vector3f(1.0f,-1.0f,0.0f);
Vertices[2]=Vector3f(0.0f,1.0f,0.0f);
glGenBuffers(1,&VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(Vertices),Vertices,GL_STATIC_DRAW);
}
staticvoidAddShader(GLuintShaderProgram,constchar*pShaderText,GLenumShaderType)
{
GLuintShaderObj=glCreateShader(ShaderType);
if(ShaderObj==0){
fprintf(stderr,"Errorcreatingshadertype%d\n",ShaderType);
exit
(1);
}
constGLchar*p[1];
p[0]=pShaderText;
GLintLengths[1];
Lengths[0]=strlen(pShaderText);
glShaderSource(ShaderObj,1,p,Lengths);
glCompileShader(ShaderObj);
GLintsuccess;
glGetShaderiv(ShaderObj,GL_COMPILE_STATUS,&success);
if(!
success){
GLcharInfoLog[1024];
glGetShaderInfoLog(ShaderObj,1024,NULL,InfoLog);
fprintf(stderr,"Errorcompilingshadertype%d:
'%s'\n",ShaderType,InfoLog);
exit
(1);
}
glAttachShader(ShaderProgram,ShaderObj);
}
staticvoidCompileShaders()
{
GLuintShaderProgram=glCreateProgram();
if(ShaderProgram==0){
fprintf(stderr,"Errorcreatingshaderprogram\n");
exit
(1);
}
stringvs,fs;
if(!
ReadFile(pVSFileName,vs)){
exit
(1);
};
if(!
ReadFile(pFSFileName,fs)){
exit
(1);
};
AddShader(ShaderProgram,vs.c_str(),GL_VERTEX_SHADER);
AddShader(ShaderProgram,fs.c_str(),GL_FRAGMENT_SHADER);
GLintSuccess=0;
GLcharErrorLog[1024]={0};
glLinkProgram(ShaderProgram);
glGetProgramiv(ShaderProgram,GL_LINK_STATUS,&Success);
if(Success==0){
glGetProgramInfoLog(ShaderProgram,sizeof(ErrorLog),NULL,ErrorLog);
fprintf(stderr,"Errorlinkingshaderprogram:
'%s'\n",ErrorLog);
exit
(1);
}
glValidateProgram(ShaderProgram);
glGetProgramiv(ShaderProgram,GL_VALIDATE_STATUS,&Success);
if(!
Success){
glGetProgramInfoLog(ShaderProgram,sizeof(ErrorLog),NULL,ErrorLog);
fprintf(stderr,"Invalidshaderprogram:
'%s'\n",ErrorLog);
exit
(1);
}
glUseProgram(ShaderProgram);
gWorldLocation=glGetUniformLocation(ShaderProgram,"gWorld");
assert(gWorldLocation!
=0xFFFFFFFF);
}
intmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(1024,768);
glutInitWindowPosition(100,100);
glutCreateWindow("Tutorial07");
InitializeGlutCallbacks();
//Mustbedoneafterglutisinitialized!
GLenumres=glewInit();
if(res!
=GLEW_OK){
fprintf(stderr,"Error:
'%s'\n",glewGetErrorString(res));
return1;
}
printf("GLversion:
%s\n",glGetString(GL_VERSION));
glClearColor(0.0f,0.0f,0.0f,0.0f);
CreateVertexBuffer();
CompileShaders();
glutMainLoop();
return0;
}
着色器脚本的代码都不变
shader.vs
#version330
layout(location=0)invec3Position;
uniformmat4gWorld;
voidmain()
{
gl_Position=gWorld*vec4(Position,1.0);
}
shader.fs
#version330
outvec4FragColor;
voidmain()
{
FragColor=vec4(1.0,0.0,0.0,1.0);
}
运行效果:
红色三角形绕圆心逆时针旋转。
八缩放变换
背景
缩放变换非常简单,它的目的是增大或者缩小物体的尺寸。
比如你想使用同一个模型来制作很多不同的物体(大小不一的树组成的树林,用的同一个模型),或者你想按照比例让物体和现实世界尺寸一致。
在上面的情形中你就需要在三个坐标轴上同等缩放顶点的位置。
当然,有时也希望物体只在一个轴上或者两个轴上缩放使模型更薄、更瘦或者更高等等。
进行缩放变换其实很简单。
我们从最开始的原变换矩阵来看,回忆平移变换矩阵的样子,我们保持结果矩阵中V1,V2和V3保持原样的办法是让变换矩阵主对角线上的值都为’1’,这样原向量一次都和1相乘之后依然保持不变,各分量之间互不影响。
所以,这里的缩放变换,只要把那些‘1’换成我们想缩放的值,原向量各分量分别乘以这些值之后就会在相应坐标轴上进行相应的缩放了,值大于1则放大,值小于1则缩小。
源代码详解
World.m[0][0]=sinf(Scale);World.m[0][1]=0.0f;World.m[0][2]=0.0f;World.m[0][3]=0.0f;
World.m[1][0]=0.0f;World.m[1][1]=sinf(Scale);World.m[1][2]=0.0f;World.m[1][3]=0.0f;
World.m[2][0]=0.0f;World.m[2][1]=0.0f;World.m[2][2]=sinf(Scale);World.m[2][3]=0.0f;
World.m[3][0]=0.0f;World.m[3][1]=0.0f;World.m[3][2]=0.0f;World.m[3][3]=1.0f;
和上个教程相比代码还是只是根据上面的描述改变了变换矩阵的内容。
可以看到,这里我们使用一个-1到1之间的一个缩放值来使物体在各坐标轴上进行缩放,(0,1]范围内三角形会在原尺寸和极小尺寸间变化,当变换矩阵对角线上的值为0时三角形彻底消失。
在[-1,0)范围内效果看上去一样但三角形翻转了,因为对角线上的值改变了顶点坐标的正负符号。
示例Demo
#include
#include
#include
#include
#include
#include"ogldev_util.h"
#include"ogldev_math_3d.h"
GLuintVBO;
GLuintgWorldLocation;
constchar*pVSFileName="shader.vs";
constchar*pFSFileName="shader.fs";
staticvoidRenderSceneCB()
{
glClear(GL_COLOR_BUFFER_BIT);
staticfloatScale=0.0f;
Scale+=0.001f;
//缩放变换矩阵
Matrix4fWorld;
World.m[0][0]=sinf(Scale);World.m[0][1]=0.0f;World.m[0][2]=0.0f;World.m[0][3]=0.0f;
World.m[1][0]=0.0f;World.m[1][1]=sinf(Scale);World.m[1][2]=0.0f;World.m[1][3]=0.0f;
World.m[2][0]=0.0f;;World.m[2][1]=0.0f;;World.m[2][2]=sinf(Scale);World.m[2][3]=0.0f;
World.m[3][0]=0.0f;;World.m[3][1]=0.0f;;World.m[3][2]=0.0f;World.m[3][3]=1.0f;
glUniformMatrix4fv(gWorldLocation,1,GL_TRUE,&World.m[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,0);
glDrawArrays(GL_TRIANGLES,0,3);
glDisableVertexAttribArray(0);
glutSwapBuffers();
}
staticvoidInitializeGlutCallbacks()
{
glutDisplayFunc(RenderSceneCB);
glutIdleFunc(RenderSceneCB);
}
staticvoidCreateVertexBuffer()
{
Vector3fVertices[3];
Vertices[0]=Vector3f(-1.0f,-1.0f,0.0f);
Vertices[1]=Vector3f(1.0f,-1.0f,0.0f);
Vertices[2]=Vector3f(0.0f,1.0f,0.0f);
glGenBuffers(1,&VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(Vertices),Vertices,GL_STATIC_DRAW);
}
staticvoidAddShader(GLuintShaderProgram,constchar*pShaderText,GLenumShaderType)
{
GLuintShaderObj=glCreateShader(ShaderType);
if(ShaderObj==0){
fprintf(stderr,"Errorcreatingshadertype%d\n",ShaderType);
exit
(1);
}
constGLchar*p[1];
p[0]=pShaderText;
GLintLengths[1];
Lengths[0]=strlen(pShaderText);
glShaderSource(ShaderObj,1,p,Lengths);
glCompileShader(ShaderObj);
GLintsuccess;
glGetShaderiv(ShaderObj,GL_COMPILE_STATUS,&success);
if(!
success){
GLcharInfoLog[1024];
glGetShaderInfoLog(ShaderObj,1024,NULL,InfoLog);
fprintf(stderr,"Errorcompilingshadertype%d:
'%s'\n",ShaderType,InfoLog);
exit
(1);
}
glAttachShader(ShaderProgram,ShaderObj);
}
staticvoidCompileShaders()
{
GLuintShaderProgram=glCreateProgram();
if(ShaderProgram==0){
fprintf(stderr,"Errorcreatingshaderprogram\n");
exit
(1);
}
stringvs,fs;
if(!
ReadFile(pVSFileName,vs)){
exit
(1);
};
if(!
ReadFile(pFSFileName,fs)){
exit
(1);
};
AddShader(ShaderProgram,vs.c_str(),GL_VERTEX_SHADER);
AddShader(ShaderProgram,fs.c_str(),GL_FRAGMENT_SHADER);
GLintSuccess=0;
GLcharErrorLog[1024]={0};
glLinkProgram(ShaderProgram);
glGetProgramiv(ShaderProgram,GL_LINK_STATUS,&Success);
if(Success==0){
glGetProgramInfoLog(ShaderProgram,sizeof(ErrorLog),NULL,ErrorLog);
fprintf(stderr,"Errorlinkingshaderprogram:
'%s'\n",ErrorLog);
exit
(1);
}
glValidateProgram(ShaderProgram);
glGetProgramiv(ShaderProgram,GL_VALIDATE_STATUS,&Success);
if(!
Success){
glGetProgramInfoLog(ShaderProgram,sizeof(ErrorLog),NULL,ErrorLog);
fprintf(stderr,"Invalidshaderprogram:
'%s'\n",ErrorLog);
exit
(1);
}
glUseProgram(ShaderProgram);
gWorldLocation=glGetUniformLocation(ShaderProgram,"gWorld");
assert(gWorldLocation!
=0xFFFFFFFF);
}
intmain(intargc,char**argv)
{
glutInit(&argc
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 一步步 OpenGL