1.掌握OpenGL的渲染架构图
OpenGL渲染架构.png
2.OpenGL数据传递的3种方式
attribute属性(颜色数据、顶点数据、纹理坐标、光照法线)不能直接传递片元着色器,需要通过GLSL代码传递。
Uniforms值可以直接传递到顶点着色器、片元着色器。
Uniforms值一般是比较统一的动作如发生旋转。
旋转的实现原理?每个顶点*渲染矩阵传到顶点着色器。
纹理:就是图片。
3.掌握OpenGL提供的存储着色器
GLShaderManager初始化
GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();
GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,GLfloat vColor[4]);
参数1: 存储着⾊器种类-单元着⾊器
参数2: 颜⾊
使⽤场景: 绘制默认OpenGL 坐标系(-1,1)下图形. 图形所有⽚段都会以⼀种颜⾊填充
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat
vColor[4]);
参数1: 存储着⾊器种类-平⾯着⾊器
参数2: 允许变化的4*4矩阵
参数3: 颜⾊
使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化).
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
参数1: 存储着⾊器种类-上⾊着⾊器
参数2: 允许变化的4*4矩阵
使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化) 颜⾊将会平滑地插⼊到顶点之间称为平滑着⾊.
4.正投影、透视投影API的使用
正投影
void SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax)
void SetPerspective(float fFov, float fAspect, float fNear, float fFar)
fFov 垂直方向上的视场角度
fAspect 窗口宽/高的比值
fNear 近裁剪面距离
fFar 远裁剪面距离
5.OpenGL上7种基本图元
GL_POINTS 单独点
GL_LINES 每对顶点定义一个线段
GL_LINE_STRIP 顶点连接不封闭
GL_LINE_LOOP 顶点连接封闭
GL_TRIANGLES 每3个顶点定义一个三角形
GL_TRIANGLE_STRIP 共用2个点的一组三角形
GL_TRIANGLE_FAN 以一个圆点、中心扇形排列、共用相邻顶点的一组三角形
三角形的环绕方式:点到点的方向是顺时针还是逆时针
在默认情况下,OpenGL 认为具有逆时针⽅向环绕的多边形为正
⾯.
glFrontFace(GL_CW);
GL_CW:告诉OpenGL 顺时针环绕的多边形为正⾯;
GL_CCW:告诉OpenGL 逆时针环绕的多边形为正⾯
三角形带 以GL_TRIANGLE_STRIP画出的一组三角形
三角形扇 以GL_TRIANGLE_FAN画出的一组三角形
6.在存储着色器的情况下渲染图形并能通过键盘控制.
#include "GLTools.h"
#include "GLMatrixStack.h" //矩阵工具类 加载单元矩阵、矩阵、矩阵相乘、压栈、出栈、缩放、平移、旋转
#include "GLFrame.h" // 矩阵工具类 位置
#include "GLFrustum.h" //矩阵工具类 设置正/透视投影矩阵 完成坐标3D-2D的映射
#include "GLBatch.h" //三角形批次类传输顶点、光照、纹理、颜色数据到存储着色器中
#include "GLGeometryTransform.h" //交换管道类 传输视图矩阵、投影矩阵、视图投影变换矩阵
#include <math.h>
#ifdef __APPLE__
#include <GLUT/GLUT.h> //mac下使用
#else
#define FREEGLUT_STATIC
#include <GL/glut.h> //linux windows 添加一个宏使用
#endif
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;
GLFrame objectFrame;
GLFrustum viewFrustum; //投影矩阵
//图元容器对象
GLBatch pointBatch;
GLBatch lineBatch;
GLBatch lineStripBatch;
GLBatch lineLoopBatch;
GLBatch triangleBatch;
GLBatch triangleStripBatch;
GLBatch triangleFanBatch;
GLGeometryTransform transformPipeline; //几何变换管道
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
int nStep = 0; //跟踪效果步骤
void setupRC() {
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
//设置变换管线以使用2个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
cameraFrame.MoveForward(-15.0f);
GLfloat vCoast[9] = { //三角形形状
3, 3, 0,
0, 3, 0,
3, 0, 0
};
//用点的形式
pointBatch.Begin(GL_POINTS, 3);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
//通过线的形式
lineBatch.Begin(GL_LINES, 3);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
//通过线段的形式
lineStripBatch.Begin(GL_LINE_STRIP, 3);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
//通过线环的形式
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
//通过三角形创建金字塔
GLfloat vpyramid[12][3] = {
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
-2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f
};
//每3个点定义一个新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vpyramid);
triangleBatch.End();
//三角形扇形--六边形
GLfloat vPoints[100][3];
int nVerts = 0;
//半径
GLfloat r = 3.0f;
//原点(x,y,z) = (0,0,0)
vPoints[nVerts][0] = 0.0f;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
//M3D_2PI 2pi 就是一个圆的意思
for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
nVerts ++; //数组下标自增,每自增一次就表示一个顶点
//弧长=半径*角度(弧度)
//x点的坐标 cos(angle) * 半径
vPoints[nVerts][0] = float(cos(angle)) * r;
//y点的坐标 sin(angle) * 半径
vPoints[nVerts][1] = float(sin(angle)) * r;
//z点的坐标
vPoints[nVerts][2] = -0.5f;
}
//结束扇形,前面一共绘制了7个顶点,包括圆心,添加闭合代码,屏蔽下面4行代码,并把绘制节点8改为7,则三角形扇形是无法闭合的
nVerts ++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 7);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
//三角形带,一个小环或圆柱段
//顶点下标
int iCounter = 0;
//半径
GLfloat radius = 3.0f;
//从0度~360度,以0.3弧度为步长
for (GLfloat angle = 0.0f; angle <= (2.0f * M3D_PI); angle += 0.3f) {
//获取圆形顶点的X Y
GLfloat x = radius * sin(angle);
GLfloat y = radius * cos(angle);
//绘制2个三角形,它们的x,y顶点一样,只是z点不一样
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = -0.5f;
iCounter ++;
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = 0.5f;
iCounter ++;
}
//关闭循环
printf("三角形带的顶点数:%d\n",iCounter);
//结束循环,在循环位置生成2个三角形
vPoints[iCounter][0] = vPoints[0][0];
vPoints[iCounter][1] = vPoints[0][1];
vPoints[iCounter][2] = -0.5;
iCounter ++;
vPoints[iCounter][0] = vPoints[1][0];
vPoints[iCounter][1] = vPoints[1][1];
vPoints[iCounter][2] = 0.5;
iCounter ++;
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
}
void drawWriteFramedBatch(GLBatch * pBatch) {
//画绿色部分 GLT_SHADER_FLAT平面着色器 变换管线,指定了2个矩阵堆栈 颜色值
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
//边框部分
//画黑色边框
//偏移深度,在同一位置要绘制填充和边线,会产生冲突,所以要偏移
glPolygonOffset(-1.0f, -1.0f);
glEnable(GL_POLYGON_OFFSET_LINE); // GL_POLYGON_OFFSET_LINE 根据函数glPolygonOffset的设置,启用线的深度偏移
//画反锯齿,让黑白好看些
glEnable(GL_LINE_SMOOTH); //GL_LINE_SMOOTH 执行后,过虑线点的锯齿
glEnable(GL_BLEND); //启用颜色混合。例如实现半透明效果
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//通过调用glPolygonMode将多边形正面或背面设为线框模式,实现线框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glLineWidth(2.5f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
//复原原本的设置
//通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE); //关闭指定功能
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
//召唤场景
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//压栈
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果存在堆栈的顶部
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
//获取矩阵堆栈顶部的值
objectFrame.GetMatrix(mObjectFrame);
//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果存在堆栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vBlack);
//GLT_SHADER_FLAT 平面着色器
switch (nStep) {
case 0:
glPointSize(4.0f); //设置点的大小
pointBatch.Draw();
glPointSize(1.0f);
break;
case 1:
glLineWidth(2.0f);
lineBatch.Draw();
glLineWidth(1.0f);
break;
case 2:
glLineWidth(2.0f);
lineStripBatch.Draw();
glLineWidth(1.0f);
break;
case 3:
glLineWidth(2.0f);
lineLoopBatch.Draw();
glLineWidth(1.0f);
break;
case 4:
drawWriteFramedBatch(&triangleBatch);
break;
case 5:
drawWriteFramedBatch(&triangleStripBatch);
break;
case 6:
drawWriteFramedBatch(&triangleFanBatch);
break;
}
//还原到以前的模型视图矩阵
modelViewMatrix.PopMatrix();
//进行缓冲区交换
glutSwapBuffers();
}
void specialKeys(int key, int x, int y) {
if (key == GLUT_KEY_UP) {
//围绕一个指定的X Y Z轴旋转
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_DOWN) {
objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_LEFT) {
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
}
glutPostRedisplay();
}
//根据空格次数,切换不同的窗口名称
void keyPressFunc(unsigned char key, int x, int y) {
if (key == 32) { //空格(Space)的ASCII码值是:32
nStep ++;
if (nStep > 6) {
nStep = 0;
}
}
switch (nStep) {
case 0:
glutSetWindowTitle("GL_POINTS");
break;
case 1:
glutSetWindowTitle("GL_LINES");
break;
case 2:
glutSetWindowTitle("GL_LINE_STRIP");
break;
case 3:
glutSetWindowTitle("GL_LINE_LOOP");
break;
case 4:
glutSetWindowTitle("GL_TRIANGLES");
break;
case 5:
glutSetWindowTitle("GL_TRIANGLE_STRIP");
break;
case 6:
glutSetWindowTitle("GL_TRIANGLE_FAN");
break;
}
glutPostRedisplay();
}
//窗口已更改大小,或刚刚创建,无论哪种情况我们都需要使用窗口维度设置视口和投影矩阵。
void changeSize(int w, int h) {
glViewport(0, 0, w, h);
//创建投影矩阵,并将它载入投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//调用顶部载入单元矩阵
modelViewMatrix.LoadIdentity();
}
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("GL_POINTS");
//注册回调函数,改变尺寸
glutReshapeFunc(changeSize);
//点击空格调用的函数
glutKeyboardFunc(keyPressFunc);
//特殊键位函数;
glutSpecialFunc(specialKeys);
//显示函数
glutDisplayFunc(renderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
return 1;
}
//绘制
setupRC();
glutMainLoop();
return 0;
}
网友评论