目录
正投影
透视投影
属性
Uniform值
GLTools的GLShaderManager所有内置着色器
点、线、多边形
GLFrustum::SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax);
GLFrustum::SetPerspective(float fFov, float fAspect, float fNear, float fFar);
对应UnityShader的顶点着色器输入结构体的数据,例如 VERTEX COLOR NORMAL TEXTURE0 TEXTURE1 对应上 OPGL的 GLT_ATTRIBUTE_VERTEX GLT_ATTRIBUTE_COLOR GLT_ATTRIBUTE_NORMAL GLT_ATTRIBUTE_TEXTURE0 GLT_ATTRIBUTE_TEXTURE1
它是针对每一个顶点而言的,即每一个顶点都携带有一个属性,不同顶点的属性是不一样的个体。
目前学习到的使用API GLShaderManager::UseStockShader(GLenum shader, ...); 时传递给 ... 的就是Uniform值,它是针对整个批次而言的,即每一个顶点都共享一个Uniform值,这是和属性的不同之处。
单位着色器 : GLShaderManager::UseStockShader(GLT_SHADER_IDENTITY, GLfloat vColor[4]);
传递Uniform:vColor颜色,着色器会使用这个颜色进行绘制,并在[-1.0,1.0]坐标系绘制,只使用GLT_ATTRIBUTE_VERTEX。
平面着色器: GLShaderManager::UseStockShader(GLT_SHADER_FLAT, GLfloat mvp[16], GLfloat vColor[4]);
传递Uniform: mvp模型视图投影矩阵和vColor颜色,着色器会使用该矩阵对顶点变换和颜色绘制,只使用GLT_ATTRIBUTE_VERTEX。
上色着色器: GLShaderManager::UseStockShader(GLT_SHADER_SHADED, GLfloat mvp[16]);
传递Uniform: mvp模型视图投影矩阵,着色器会使用该矩阵对顶点变换,会使用GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_COLOR。多了一个顶点颜色属性进行上色。
默认光源着色器: GLShaderManager::UseStockShader(GLT_SHADER_DEFAULT_LIGHT, GLfloat mv[16], GLfloat p[16], GLfloat vColor[4]);
传递Uniform: mv模型视图矩阵、p投影矩阵和vColor颜色,着色器会使用这些参数进行正确的阴影、光照渲染和上色,会使用GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_NORMAL。
点光源着色器: GLShaderManager::UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, GLfloat mv[16], GLfloat p[16], GLfloat vLightPos[3], GLfloat vColor[4]);
传递Uniform: mv模型视图矩阵、p投影矩阵、视图点光源位置和颜色,着色器会使用这些参数进行阴影、光照、上色,会使用GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_NORMAL。
纹理替换矩阵:GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_REPLACE, GLfloat mvpMatrix[16], GLint nTextureUnit);
书上解释的不太清楚,目前姑且认为是一种替换纹理的着色器,替换的是nTextureUnit参数(Int)索引指定的纹理所应用到的顶点进行mvpMatrix矩阵的变换。
纹理调整着色器:GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_MODULATE, GLfloat mvpMatrix[16], GLfloat vColor, GLint nTextureUnit);
书上写的vColor居然不是vColor[4],待确认内容... 大体意思是用vColor乘以一个nTextureUnit指定的纹理颜色? mvpMatrix[16]不知道干嘛的,会使用GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_TEXTURE0。
纹理光源着色器:GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, GLfloat mvMatrix, GLfloat pMatrix[16], GLfloat vLightPos[3], GLfloat vBaseColor[4], GLint nTextureUnit);
书上写的mvMatrix进入不是mvMatrix[16],将一个纹理通过漫反射照明计算进行调整(乘以vColor?),光线用的是点光源位置,会使用GLT_ATTRIBUTE_VERTEX、GLT_ATTRIBUTE_NORMAL和GLT_ATTRIBUTE_TTEXTURE0。
以上内容暂时记录更详细的理解后面会经常用会到时理解清楚。
GL_Point 点 glPointSize(GLfloat size)函数定义点的大小,glGetFloatv(GL_POINT_SIZE_RANGE, sizes) 获取支持的点大小范围 glGetFloatv(GL_POINT_SIZE_GRANULARITY, &step)获取支持的点大小增量。
GL_LINES 每一对点形成的线段 glEnable(GL_PROMGRAM_POINT_SIZE)启用点大小模式 在程序中着色器代码里用gl_PointSize=5.0 设置点大小,案例设置的是4.0
GL_LINE_STRIP 从第一个顶点依次经过每个顶点绘制成的线条 glLineWidth(GLfloat width); 设置线宽度
GL_LINE_LOOP 和GL_LINE_STRIP相同,但最后一个顶点和第一个顶点也连起来了
GL_TRIANGLES 每3个顶点定义一个新的三角形
GL_TRIANGLE_STRIP 共用一个三角形边顶点(strip条带)上的顶点的一组三角形(即会出现共用顶点的三角形,在GL_TRIANGLE基础上把空隙连上了和GL_LINE_STRIP一样意思),绘制一串相连的三角形
GL_TRIANGLE_FAN 以一个圆点为中心呈扇形排列,共用相邻顶点的一组三角形。(即第一个v0顶点和其他2个v1和v2顶点构成第一个三角形后 之后每一次增加的顶点都会与v0和相邻顶点构成一个新的三角形,具体看示例图)
// Primitieves.cpp
// OpenGL SuperBible, Chapter 2
// Demonstrates the 7 Geometric Primitives
// Program by Richard S. Wright Jr.
#pragma comment(lib, "gltools.lib")
#include // OpenGL toolkit
#include
#include
#include
#include
#include
#include
#ifdef __APPLE__
#include
#else
#define FREEGLUT_STATIC
#include
#endif
// An assortment of needed classes
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;
M3DMatrix44f shadowMatrix;
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
// Keep track of effects step
int nStep = 0;
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.
void SetupRC()
{
// Black background
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
cameraFrame.MoveForward(-15.0f);
//
// Some points, more or less in the shape of Florida
GLfloat vCoast[24][3] = { {2.80, 1.20, 0.0 }, {2.0, 1.20, 0.0 },
{2.0, 1.08, 0.0 }, {2.0, 1.08, 0.0 },
{0.0, 0.80, 0.0 }, {-.32, 0.40, 0.0 },
{-.48, 0.2, 0.0 }, {-.40, 0.0, 0.0 },
{-.60, -.40, 0.0 }, {-.80, -.80, 0.0 },
{-.80, -1.4, 0.0 }, {-.40, -1.60, 0.0 },
{0.0, -1.20, 0.0 }, { .2, -.80, 0.0 },
{.48, -.40, 0.0 }, {.52, -.20, 0.0 },
{.48, .20, 0.0 }, {.80, .40, 0.0 },
{1.20, .80, 0.0 }, {1.60, .60, 0.0 },
{2.0, .60, 0.0 }, {2.2, .80, 0.0 },
{2.40, 1.0, 0.0 }, {2.80, 1.0, 0.0 } };
// Load point batch
pointBatch.Begin(GL_POINTS, 24);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
// Load as a bunch of line segments
lineBatch.Begin(GL_LINES, 24);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
// Load as a single line segment
lineStripBatch.Begin(GL_LINE_STRIP, 24);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
// Single line, connect first and last points
lineLoopBatch.Begin(GL_LINE_LOOP, 24);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
// For Triangles, we'll make a Pyramid
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 };
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
// For a Triangle fan, just a 6 sided hex. Raise the center up a bit
GLfloat vPoints[100][3]; // Scratch array, more than we need
int nVerts = 0;
GLfloat r = 3.0f;
vPoints[nVerts][0] = 0.0f;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
nVerts++;
vPoints[nVerts][0] = float(cos(angle)) * r;
vPoints[nVerts][1] = float(sin(angle)) * r;
vPoints[nVerts][2] = -0.5f;
}
// Close the fan
nVerts++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
// Load it up
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
// For triangle strips, a little ring or cylinder segment
int iCounter = 0;
GLfloat radius = 3.0f;
for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
{
GLfloat x = radius * sin(angle);
GLfloat y = radius * cos(angle);
// Specify the point and move the Z value up a little
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = -0.5;
iCounter++;
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = 0.5;
iCounter++;
}
// Close up the loop
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++;
// Load the triangle strip
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
}
void DrawWireFramedBatch(GLBatch* pBatch)
{
// Draw the batch solid green
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
// Draw black outline
glPolygonOffset(-1.0f, -1.0f); // Shift depth values
glEnable(GL_POLYGON_OFFSET_LINE);
// Draw lines antialiased
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Draw black wireframe version of geometry
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glLineWidth(2.5f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
// Put everything back the way we found it
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
// Called to draw scene
void RenderScene(void)
{
// Clear the window with current clearing color
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);
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:
DrawWireFramedBatch(&triangleBatch);
break;
case 5:
DrawWireFramedBatch(&triangleStripBatch);
break;
case 6:
DrawWireFramedBatch(&triangleFanBatch);
break;
}
modelViewMatrix.PopMatrix();
// Flush drawing commands
glutSwapBuffers();
}
// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP)
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();
}
// A normal ASCII key has been pressed.
// In this case, advance the scene when the space bar is pressed
void KeyPressFunc(unsigned char key, int x, int y)
{
if (key == 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();
}
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
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();
}
// Main entry point for GLUT based programs
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;
}
注意 #pragma comment(lib, "gltools.lib") 只是我个人项目所需,如果有报错可注释掉.