美文网首页iOS视觉
六 OpenGL的渲染技巧

六 OpenGL的渲染技巧

作者: 王俏 | 来源:发表于2020-08-04 18:00 被阅读0次

1.绘制甜甜圈,并通过键盘控制旋转

  • 定义变量
//设置角色帧,作为相机
GLFrame             viewFrame;
//使用GLFrustum类来设置透视投影
GLFrustum           viewFrustum;
//三角形批次类
GLTriangleBatch     torusBatch;
//模型视图矩阵
GLMatrixStack       modelViewMatix;
//投影矩阵
GLMatrixStack       projectionMatrix;
//着色器管道
GLGeometryTransform transformPipeline;
//着色器管理器
GLShaderManager     shaderManager;
  • main函数,初始化GLUT,初始化显示模式,创建窗口,设置回调函数,开启runloop
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("Geometry Test Program");
    glutReshapeFunc(ChangeSize);
    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;
}

  • SetupRC 设置背景色,初始化着色器管理器,设置观察者视角,创建甜甜圈
void SetupRC()
{
    //1.设置背景颜色
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f );
    
    //2.初始化着色器管理器
    shaderManager.InitializeStockShaders();
    
    //3.将相机向后移动10个单元:肉眼到物体之间的距离
    viewFrame.MoveForward(10);
    
    
    //4.创建一个甜甜圈
    //void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
    //参数1:GLTriangleBatch 容器帮助类
    //参数2:外边缘半径
    //参数3:内边缘半径
    //参数4、5:主半径和从半径的细分单元数量
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    
    //5.点的大小(方便点填充时,肉眼观察)
    glPointSize(4.0f);
}
  • ChangeSize窗口改变大小时调用,设置视口,投影模式,初始化投影矩阵和渲染管线
void ChangeSize(int w, int h)
{
    //1.防止h变为0
    if(h == 0)
        h = 1;
    
    //2.设置视口窗口尺寸
    glViewport(0, 0, w, h);
    

    // 3.设置透视模式,初始化其透视矩阵
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
    
    //4.把透视矩阵加载到透视矩阵对阵中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //5.初始化渲染管线
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}
  • RenderScene渲染场景(清缓存,设置MVP矩阵,渲染颜色,图元组合模式)
void RenderScene()
{
    //1.清除窗口和深度缓冲区
    //不清空颜色/深度缓冲区时.渲染会造成什么问题-->残留数据,颜色混合
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //2.把摄像机矩阵压入模型矩阵中
    modelViewMatix.PushMatrix(viewFrame);

    //3.设置绘图颜色
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    
    //4.
    //使用平面着色器
    //参数1:平面着色器
    //参数2:模型视图投影矩阵
    //参数3:颜色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
    
    //5.绘制
    torusBatch.Draw();

    //6.出栈 绘制完成恢复
    modelViewMatix.PopMatrix();
    
    //7.交换缓存区
    glutSwapBuffers();
}
  • SpecialKeys通过上下左右键移动控制观察者角度
void SpecialKeys(int key, int x, int y)
{
    //1.判断方向
    if(key == GLUT_KEY_UP)
        //2.根据方向调整观察者位置 绕Y轴选择-5度
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
    
    if(key == GLUT_KEY_DOWN) //绕Y轴选择5度
        viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);
    
    if(key == GLUT_KEY_LEFT) //绕X轴选择-5度
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);
    
    if(key == GLUT_KEY_RIGHT)//绕X轴选择5度
        viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);
    
    //3.重新刷新
    glutPostRedisplay();
}

渲染过程产⽣的问题

image image

问题原因:

a) 从观察者视角,不可见部分也进行了渲染--->不可见区域应该丢弃,即隐藏面消除(Hidden surface elimination)

b) 从观察者视角,位于同一个平面的像素点,渲染出现问题--->开启深度测试

2. 油画渲染

先绘制场景中的离观察者较远的物体,再绘制较近的物体

弊端:

远近离观察者一致时,无法处理--->深度测试

多余的去绘制 --->正背面剔除

3. 正面&背⾯剔除

何为正面?


image

默认从观察者角度,逆时针的面为正面,开发者也可以修改和指定正面,但此状态是全局的,一处修改其他渲染位置同时遵循指定的正面规则

正面&背⾯剔除,就是检查所有正面朝向观察者的面,渲染它们.而丢弃背面朝向的面. 同时用户也可以选择剔除哪一个面

//开启表⾯剔除(默认背面剔除)
void glEnable(GL_CULL_FACE);

//关闭表面剔除(默认背面剔除)
void glDisable(GL_CULL_FACE);


//⽤户选择剔除那个面(正面/背面) 
//mode参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默认GL_BACK ⽤户指定绕序那个为正面
void glCullFace(GLenum mode);

//指定正面
//GL_CW:指定顺时针环绕的多边形为正面;
//GL_CCW:指定逆时针环绕的多边形为正面
//mode参数为: GL_CW,GL_CCW,默认值:GL_CCW
void glFrontFace(GLenum mode);

//剔除正面,方法一:
glCullFace(GL_BACK);
glFrontFace(GL_CW); 

//剔除正面,方法二:
glCullFace(GL_FRONT);

4. 深度测试

关于深度测试,详见浅谈图形图像渲染中的深度缓冲区和深度测试

6. 裁剪

只刷新屏幕上发生变化的部分--> 指定一个裁剪框,不在裁剪框的片元被丢弃,只有裁剪区域内的片元才有可能进入帧缓冲。

//1 开启裁剪测试 
glEnable(GL_SCISSOR_TEST);

//2.关闭裁剪测试 
glDisable(GL_SCISSOR_TEST);

//3.指定裁剪窗⼝
void glScissor(Glint x,Glint y,GLSize width,GLSize height);
//x,y:指定裁剪框左下角位置; width , height:指定裁剪尺⼨

7. 颜⾊混合

我们把OpenGL 渲染时会把颜⾊值存在颜⾊缓存区中,每个片段的深度值也是放在深度缓冲区。当深度 缓冲区被关闭时,新的颜色将简单的覆盖原来颜色缓存区存在的颜色值,当深度缓冲区再次打开时,新 的颜⾊⽚段只有当它们比原来的值更更接近邻近的裁剪平面才会替换原来的颜色片段。

颜色混合的详解见: 浅析OpenGL的颜色混合

相关文章

  • OpenGL(六)-- 渲染技巧:正背面剔除、深度测试、多边形偏

    OpenGL(六)-- 渲染技巧:正背面剔除、深度测试、多边形偏移、颜色混合 通过一个基础案例来了解这些渲染技巧:...

  • 六 OpenGL的渲染技巧

    1.绘制甜甜圈,并通过键盘控制旋转 定义变量 main函数,初始化GLUT,初始化显示模式,创建窗口,设置回调函数...

  • 六、OpenGL 渲染技巧:深度测试、多边形偏移、 混合

    OpenGL + OpenGL ES +Metal 系列文章汇总 深度测试 在上一篇五、OpenGL 渲染技巧:正...

  • OpenGL渲染技巧

      在OpenGL渲染中, 我们会碰到各种各样的问题,所以也会对应的产生各种各样的渲染技巧,接下来就介绍我们最经常...

  • OpenGL渲染技巧

    1、渲染过程产⽣的问题 在绘制3D场景的时候,我们需要决定哪些部分是对观察者 可见的,或者哪些部分是对观察者不可⻅...

  • OpenGL渲染技巧

    1、隐藏面消除 在渲染3D场景过程中可能会产生以下问题 我们需要决定哪些部分是对观察者可⻅的,或者哪些部分是对观察...

  • OpenGL渲染技巧

    OpenGL渲染技巧 了解了OpenGL的渲染流程和常用API后,就可以简单的绘制出图形了。但是在绘制中可能会碰到...

  • OpenGL渲染技巧

    首先,我们来绘制一个3D图形“甜甜圈”,示例程序运行效果如下: 咋看,似乎没什么问题。但当我们试着向右旋转它的时候...

  • OpenGL渲染技巧

    深度测试 在之前我们已经讲过深度测试的大部分内容,这次就完善一下之前的内容。首先深度测试解决的问题:当我们绘制的图...

  • OpenGL渲染技巧

    先引入一个案例: 设置一个甜甜圈,为了体现出阴影效果和立体效果,选取默认光源着色器开始渲染: 效果如下: 可以看到...

网友评论

    本文标题:六 OpenGL的渲染技巧

    本文链接:https://www.haomeiwen.com/subject/gwwwrktx.html