1.OpenGL学习误区?
如果不能精通那些3D图形数学知识,会让我们寸步难行。其实不然,我们不懂汽车结构不是每天还在开车嘛,但是我们需要懂得如何保养车,所以我们最好对汽车有足够的了解。同理我们至少要理解矩阵和向量。
2.3D数学的用处?
是OpenGL、ARKit、Unity3D、游戏开发必须学习的一块。
3.M3DVector3f 表示一个三维向量
M3DVector4f 表示一个四维向量
单位向量:
(1,0,0)
单位矩阵:
(1,0,0,
0,1,0,
0,0,1)
1,2,3
pushMatrix();1,2,3
1,2,3
pushMatrix(4);1,2,3,4
1,2,3
popMatrix();1,2,3
点乘运算返回2个向量之间的夹角
叉乘运算返回1个新的向量,这个新的向量与原来的2个向量垂直。叉乘不满足交换律所以要注意先后顺序
A0 A1 A2 A3
[ A4 A5 A6 A7 ]
A8 A9 A10 A11
A12 A13 A14 A15
行矩阵
A0 A4 A8 A12
[A1 A5 A9 A13 ]
A2 A6 A10 A14
A3 A7 A11 A15
列矩阵
行矩阵转置后是列矩阵
5.1个4*4的矩阵如何在3D空间中表示一个位置和方向的?
列向量进行了特别的标注,矩阵的最后一行都为0,只有最后一个元素为1.
6.将1个向量乘以一个单位矩阵得到的结果还是原来的矩阵。
4 1 0 0 0 4
[ 5 ] [ 0 1 0 0 ] [ 5 ]
2 0 0 1 0 2
1 0 0 0 1 1
7.注意理解代码中的常用矩阵函数如压栈、出栈等。
1.图形移动-矩阵变换
#include "GLShaderManager.h"
#include "GLTools.h"
#include "math3d.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLBatch squareBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = {
- blockSize, - blockSize, 0.0f,
blockSize, - blockSize, 0.0f,
blockSize, blockSize, 0.0f,
- blockSize, blockSize, 0.0f
};
GLfloat xPos = 0;
GLfloat yPos = 0;
//为程序做一次性的设置
void setupRC() {
//初始化
glClearColor(0, 0, 1, 1);
shaderManager.InitializeStockShaders();
//加载三角形
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
}
//计算移动距离和碰撞检测
void specialKeys(int key, int x, int y) {
GLfloat stepSize = 0.025f;
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 + blockSize) {
xPos = -1 + blockSize;
}
if (xPos > 1 - blockSize) {
xPos = 1 - blockSize;
}
if (yPos < - 1 + blockSize) {
yPos = -1 + blockSize;
}
if (yPos > 1 - blockSize) {
yPos = 1 - blockSize;
}
glutPostRedisplay();
}
//开始渲染
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = { 1, 0, 0, 1 };
M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;
//平移 xPos, yPos
m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0);
//每次重绘时旋转5度
static float yRot = 0;
yRot += 5;
m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(yRot), 0, 0, 1);
//将平移旋转的结果合并到mFinalTransform中
m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);
//将矩阵结果提交到固定着色器(平面着色器)中
shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vRed);
squareBatch.Draw();
glutSwapBuffers();
}
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
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 Block with Arrow Keys");
GLenum err = glewInit();
if (err != GLEW_OK) {
fprintf(stderr, "Error:%s\n",glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(renderScene);
glutSpecialFunc(specialKeys);
setupRC();
glutMainLoop();
return 0;
}
2.使用矩阵创建几何图形(objectFrame 和objectFrame+CameraFrame))
#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include "StopWatch.h"
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame; //观察者位置
GLFrame objectFrame; //世界坐标位置
GLFrustum viewFrustum; //视景体,用来构造投影矩阵
GLTriangleBatch triangle; //三角形批次类
GLTriangleBatch sphereBatch; //球
GLTriangleBatch torusBatch; //环
GLTriangleBatch cylinderBatch; //圆柱
GLTriangleBatch coneBatch; //锥
GLTriangleBatch diskBatch; //磁盘
GLGeometryTransform transformPipeline;
M3DMatrix44f shadowMatrix;
GLfloat vGreen[] = { 0, 1, 0, 1 };
GLfloat vBlack[] = { 0, 0, 0, 1 };
int nStep = 0;
//必要初始化
void setupRC() {
glClearColor(0.7, 0.7, 0.7, 1);
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
objectFrame.MoveForward(15);//将物体向屏幕外移动15
//使用三角形批次类构造图形对象
/*
球 void gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);
sphereBatch 三角形批次类对象
fRadius 球体半径
iSlices 从球体底部堆叠到顶部的 三角形带数量;其实球体是一圈一圈三角形带组成的
iStacks 围绕球体一圈排列的三角形对数 几层三角形带
建议:一个对称性好的球体的片段数量是堆叠数量的2倍即iStacks =iSlices * 2
*/
gltMakeSphere(sphereBatch, 3, 10, 20);
/*
环面
void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
majorRadius 外半径 minorRadius内半径 numMajor主半径三角形数量 numMinor小半径三角形数量
*/
gltMakeTorus(torusBatch, 3, 0.75, 15, 15);
//圆柱
gltMakeCylinder(cylinderBatch, 2, 2, 3, 15, 3);
//圆锥 一端半径为0,另一端半径可指定
gltMakeCylinder(coneBatch, 2, 0, 3, 13, 5);
//磁盘 100 100 的效果会是什么样子的呢
gltMakeDisk(diskBatch, 1.5, 3, 100, 100);
}
void drawWriteFramedBatch(GLTriangleBatch *pBatch) {
//绘制图形
//1.平面着色器,绘制三角形
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
//传过来的参数对应不同的图形Batch
pBatch->Draw();
//画出黑色轮廓
//2.开启多边形偏移
glEnable(GL_POLYGON_OFFSET_LINE);
//多边形模型(背面、线) 将多边形背面设为线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//开启多边形偏移(设置偏移数量)
glPolygonOffset(-1, -1);
glLineWidth(2.5);
//3.开启混合功能(颜色混合&抗锯齿功能)
glEnable(GL_BLEND);
//开启处理线段抗锯齿功能
glEnable(GL_LINE_SMOOTH);
//设置颜色混合因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//4.平面着色器绘制线条
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
//5.恢复多边形模式和深度测试
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
//开始渲染
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// modelViewMatrix.PushMatrix(objectFrame);
//或
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame);
//判断目前绘制第几个图形
switch (nStep) {
case 0:
drawWriteFramedBatch(&sphereBatch);
break;
case 1:
drawWriteFramedBatch(&torusBatch);
break;
case 2:
drawWriteFramedBatch(&cylinderBatch);
break;
case 3:
drawWriteFramedBatch(&coneBatch);
break;
case 4:
drawWriteFramedBatch(&diskBatch);
break;
}
modelViewMatrix.PopMatrix();
glutSwapBuffers();
}
//上下左右移动图形
void specialKeys(int key, int x, int y) {
if (key == GLUT_KEY_UP) {
//移动世界坐标系,而不是去移动物体,将世界坐标系在X方向移动-5
objectFrame.RotateWorld(m3dDegToRad(-5), 1, 0, 0);
}
if (key == GLUT_KEY_DOWN) {
objectFrame.RotateWorld(m3dDegToRad(5), 1, 0, 0);
}
if (key == GLUT_KEY_LEFT) {
objectFrame.RotateWorld(m3dDegToRad(-5), 0, 1, 0);
}
if (key == GLUT_KEY_RIGHT) {
objectFrame.RotateWorld(m3dDegToRad(5), 0, 1, 0);
}
glutPostRedisplay();
}
//点击空格切换渲染图形
void keyPressFunc(unsigned char key, int x, int y) {
if (key == 32) {
nStep ++;
if (nStep > 4) {
nStep = 0;
}
}
switch (nStep) {
case 0:
glutSetWindowTitle("Sphere");
break;
case 1:
glutSetWindowTitle("Torus");
break;
case 2:
glutSetWindowTitle("Cylinder");
break;
case 3:
glutSetWindowTitle("Cone");
break;
case 4:
glutSetWindowTitle("Disk");
break;
}
glutPostRedisplay();
}
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
//1.视口
glViewport(0, 0, w, h);
//2.透视投影
viewFrustum.SetPerspective(35, float(w) / float(h), 1, 500);
//矩阵堆栈加载透视投影矩阵
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//3.矩阵堆栈加载单元矩阵
modelViewMatrix.LoadIdentity();
//4.transformPipeline管理矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
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("Sphere");
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(keyPressFunc);
glutSpecialFunc(specialKeys);
glutDisplayFunc(renderScene);
GLenum err = glewInit();
if (err != GLEW_OK) {
fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
return 1;
}
setupRC();
glutMainLoop();
return 0;
}
网友评论