目录
混合和抗锯齿
混合案例
抗锯齿案例
多重采样【木有案例】
优化
混合和抗锯齿
混合案例
// Blending.cpp
// Move a Block based on arrow key movements,
// Blend it with background blocks
#pragma comment(lib, "gltools.lib")
#include <GLTools.h> // OpenGL toolkit
#include <GLShaderManager.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLBatch squareBatch;
GLBatch greenBatch;
GLBatch redBatch;
GLBatch blueBatch;
GLBatch blackBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f };
///
// 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(1.0f, 1.0f, 1.0f, 1.0f);
shaderManager.InitializeStockShaders();
// Load up a triangle fan
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
GLfloat vBlock[] = { 0.25f, 0.25f, 0.0f,
0.75f, 0.25f, 0.0f,
0.75f, 0.75f, 0.0f,
0.25f, 0.75f, 0.0f };
greenBatch.Begin(GL_TRIANGLE_FAN, 4);
greenBatch.CopyVertexData3f(vBlock);
greenBatch.End();
GLfloat vBlock2[] = { -0.75f, 0.25f, 0.0f,
-0.25f, 0.25f, 0.0f,
-0.25f, 0.75f, 0.0f,
-0.75f, 0.75f, 0.0f };
redBatch.Begin(GL_TRIANGLE_FAN, 4);
redBatch.CopyVertexData3f(vBlock2);
redBatch.End();
GLfloat vBlock3[] = { -0.75f, -0.75f, 0.0f,
-0.25f, -0.75f, 0.0f,
-0.25f, -0.25f, 0.0f,
-0.75f, -0.25f, 0.0f };
blueBatch.Begin(GL_TRIANGLE_FAN, 4);
blueBatch.CopyVertexData3f(vBlock3);
blueBatch.End();
GLfloat vBlock4[] = { 0.25f, -0.75f, 0.0f,
0.75f, -0.75f, 0.0f,
0.75f, -0.25f, 0.0f,
0.25f, -0.25f, 0.0f };
blackBatch.Begin(GL_TRIANGLE_FAN, 4);
blackBatch.CopyVertexData3f(vBlock4);
blackBatch.End();
}
// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0]; // Upper left X
GLfloat blockY = vVerts[7]; // Upper left Y
if (key == GLUT_KEY_UP)
blockY += stepSize;
if (key == GLUT_KEY_DOWN)
blockY -= stepSize;
if (key == GLUT_KEY_LEFT)
blockX -= stepSize;
if (key == GLUT_KEY_RIGHT)
blockX += stepSize;
// Collision detection
if (blockX < -1.0f) blockX = -1.0f;
if (blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;;
if (blockY < -1.0f + blockSize * 2) blockY = -1.0f + blockSize * 2;
if (blockY > 1.0f) blockY = 1.0f;
// Recalculate vertex positions
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize * 2;
vVerts[3] = blockX + blockSize * 2;
vVerts[4] = blockY - blockSize * 2;
vVerts[6] = blockX + blockSize * 2;
vVerts[7] = blockY;
vVerts[9] = blockX;
vVerts[10] = blockY;
squareBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
///
// 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);
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
greenBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
redBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
blueBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
blackBatch.Draw();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
squareBatch.Draw();
glDisable(GL_BLEND);
// Flush drawing commands
glutSwapBuffers();
}
///
// 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);
}
///
// 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);
glutInitWindowSize(800, 600);
glutCreateWindow("Move Block with Arrow Keys to see blending");
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
SetupRC();
glutMainLoop();
return 0;
}
抗锯齿案例
// Blending.cpp
// Move a Block based on arrow key movements,
// Blend it with background blocks
#include <GLTools.h> // OpenGL toolkit
#include <GLShaderManager.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLBatch squareBatch;
GLBatch greenBatch;
GLBatch redBatch;
GLBatch blueBatch;
GLBatch blackBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f};
///
// 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(1.0f, 1.0f, 1.0f, 1.0f );
shaderManager.InitializeStockShaders();
// Load up a triangle fan
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
GLfloat vBlock[] = { 0.25f, 0.25f, 0.0f,
0.75f, 0.25f, 0.0f,
0.75f, 0.75f, 0.0f,
0.25f, 0.75f, 0.0f};
greenBatch.Begin(GL_TRIANGLE_FAN, 4);
greenBatch.CopyVertexData3f(vBlock);
greenBatch.End();
GLfloat vBlock2[] = { -0.75f, 0.25f, 0.0f,
-0.25f, 0.25f, 0.0f,
-0.25f, 0.75f, 0.0f,
-0.75f, 0.75f, 0.0f};
redBatch.Begin(GL_TRIANGLE_FAN, 4);
redBatch.CopyVertexData3f(vBlock2);
redBatch.End();
GLfloat vBlock3[] = { -0.75f, -0.75f, 0.0f,
-0.25f, -0.75f, 0.0f,
-0.25f, -0.25f, 0.0f,
-0.75f, -0.25f, 0.0f};
blueBatch.Begin(GL_TRIANGLE_FAN, 4);
blueBatch.CopyVertexData3f(vBlock3);
blueBatch.End();
GLfloat vBlock4[] = { 0.25f, -0.75f, 0.0f,
0.75f, -0.75f, 0.0f,
0.75f, -0.25f, 0.0f,
0.25f, -0.25f, 0.0f};
blackBatch.Begin(GL_TRIANGLE_FAN, 4);
blackBatch.CopyVertexData3f(vBlock4);
blackBatch.End();
}
// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0]; // Upper left X
GLfloat blockY = vVerts[7]; // Upper left Y
if(key == GLUT_KEY_UP)
blockY += stepSize;
if(key == GLUT_KEY_DOWN)
blockY -= stepSize;
if(key == GLUT_KEY_LEFT)
blockX -= stepSize;
if(key == GLUT_KEY_RIGHT)
blockX += stepSize;
// Collision detection
if(blockX < -1.0f) blockX = -1.0f;
if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;;
if(blockY < -1.0f + blockSize * 2) blockY = -1.0f + blockSize * 2;
if(blockY > 1.0f) blockY = 1.0f;
// Recalculate vertex positions
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize*2;
vVerts[3] = blockX + blockSize*2;
vVerts[4] = blockY - blockSize*2;
vVerts[6] = blockX + blockSize*2;
vVerts[7] = blockY;
vVerts[9] = blockX;
vVerts[10] = blockY;
squareBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
///
// 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);
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
greenBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
redBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
blueBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
blackBatch.Draw();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
squareBatch.Draw();
glDisable(GL_BLEND);
// Flush drawing commands
glutSwapBuffers();
}
///
// 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);
}
///
// 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);
glutInitWindowSize(800, 600);
glutCreateWindow("Move Block with Arrow Keys to see blending");
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
SetupRC();
glutMainLoop();
return 0;
}
抗锯齿是利用混合来混合周围像素达到抗锯齿目的,在任何图元的边缘上,像素颜色会稍微延伸到相邻的像素。
/
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); //关闭抗锯齿线段
}
带注释的就是主要解释代码内容。
抗锯齿还有GL_POINT_SMOOTH、GL_POLYGONE_SMOOTH 对应点抗锯齿和多变现抗锯齿,但多边形抗锯齿往往不好用,因此多重采样来了。
设定抗锯齿算法(GL_NICEST 最好的):glHint(GL_POINT_SMOOTH_HINT, GL_NICEST) , 此外还有GL_LINE_SMOOTH_HINT、GL_POLYGONE_SMOOTH_HINT, 以及 GL_FASTEST 最快速度抗锯齿算法。
多重采样【木有案例】
书上解释说是 点和线的抗锯齿是支持的比较好的,但多边形的平滑抗锯齿处理就支持的不是很好,原因是抗锯齿处理是基于混合操作的,这就需要从前到后对所有的图元进行排序,这是非常麻烦的!
问题来了! 为什么要从前到后排序图元呢?因为开启了混合!在学习UnityShader时我们已经认识到 透明队列 就是开启混合的,所以它能透明嘛,而透明队列 必然会进行 从前到后 渲染。 (前是指摄像机更远的地方,后是指离摄像机更近的地方, 而这个排序仅仅只是物体个体的排序,而不是像素级别的排序,如果是像素级别的排序的话 那就不会有深度测试这么一个玩意了。因为很难做到 像素级的排序,因为做不到 从而出现各种奇怪的问题 ,比如 2个互相穿透的半透明物体,怎么处理这些物体的抗锯齿?可能这时就出现问题了,比如 本应该在后渲染的片段 变成了 在前面渲染了, 就会导致 抗锯齿混合时 并没有正确混合到周围那些像素, 因为那些像素还没被渲染出来。。。(大概是这个意思)
OpenGL 1.3特性 多重采样技术,需要额外增多一个缓冲区“多重采样缓冲区”。
所有图元在每个像素上都进行了多次采样,其结果就存储在这个缓冲区中。每次当这个像素进行更新时,这些采样值进行解析,以产生一个单独的值。从程序员角度看,它是自动的,属于“幕后发生的事情”。
这种处理会带来额外的内存和处理器开销,有可能对性能造成影响。有些OpengGL实现可能不支持多渲染环境中的多重采样。
多重采样我个人理解与抗锯齿差别在于 ,抗锯齿是混合,必须开启混合,而多重采样我认为它不是混合了,而是融合更恰当,类似于 把周围9个像素的颜色 相加 取平均 这种事情,可能会比单纯的混合更加简单地处理抗锯齿问题。
代码上:glutInitDisplayMode(GLUT_MULTISAMPLE | GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 开启多重采样缓冲区 、双缓存区、 颜色缓冲区、 深度缓冲区。
glEnable(GL_MULTISAMPLE) 开启多重采样 ,此时会忽略点、直线、多边形的平滑特性 即 glEnable(GL_POINT_SMOOTH) 那些会不生效了。
因为多重采样比抗锯齿混合处理更耗,基本上绘制点和线时 都禁用多重采样,开启点和线的抗锯齿SMOOTH混合处理,而绘制多边形时开启多重采样。
下面内容有点懵逼
多重采样缓冲区在默认情况下使用片段的RGB值,并不包括Alpha。可以通过glEnable(下面3个值之一)来修改这个行为
GL_SAMPLE_ALPHA_TO_COVERAGE 使用alpha值
GL_SAMPLE_ALPHA_TO_ON 使用alpha值并设置为1使用它
GL_SAMPLE_COVERAGE 使用glSampleCoverage函数所设置的值
当启动glEnable(GL_SAMPLE_COVERAGE)时 可用 glSampleCoverage(GLclampf value , GLboolean invert);设定特定值,它是与片段覆盖值进行按位于操作的结果
Glclampf是[0,32]位的浮点数
优化
glEnable 开启 和 glDisable 关闭状态 都会对渲染的性能造成影响,可以将那些相同状态的渲染几何图形代码放在一起,避免不必要的glEnable和glDisbale。