3.OpenGL渲染技巧

2020-11-27  本文已影响0人  bytebytebyte

1.渲染过程产生的问题
看到了不透明墙壁后面的东西,不应该渲染墙壁后的东西(隐藏面消除)

2.油画渲染
距离观察者由远及近的绘制物体,可以解决。
但是这出现了新的问题,如果3个三角形互相叠加,油画算法将无法渲染。

3.正背面剔除
OpenGL可以检查朝向观察者的面并渲染它们,而丢弃背面。
OpenGL如何区分正背面?
通过分析顶点数据的顺序。

4.深度测试
深度:3D世界中像素点距离摄像机的距离。
深度缓冲区:一块内存区域、存储着每个像素点的深度值,值越大距离摄像机越远。
为何需要深度缓冲区?绘制顺序就不重要了。
深度测试:是否绘制物体表面,表面深度值和当前缓冲区深度值比较,大于则丢弃,否则更新像素颜色值和深度值。

5.多边形模型
6.多边形偏移
7.裁剪
8.颜色混合

1.谈谈图形图像渲染中的深度缓冲区?
一块内存区域、存储着每个像素点的深度值,值越大距离摄像机越远。
为何需要深度缓冲区?绘制顺序就不重要了。

2.阐述隐藏面消除解决方案?
正背面剔除、深度测试

3.阐述深度缓冲区带来的隐患、解决方案、预防方案?
原因:深度缓冲区的限制导致深度相差很小。
隐患:交错闪烁出现2个画面
解决方案:让深度值之间产生间隔,在执行深度测试前将立方体的深度值做一些细微的增加,区分重叠的2个图形深度值。
第一步:Polygon Offset方式解决。
glEnable(GL_POLYGON_OFFSET_FILL)
第二步:指定偏移量
void glPolygonOffset(Glfloat factor,Glfloat units);
第三步: 关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)

预防方案:
不要将2个物体靠的太近;将裁剪面设置的离观察者远一些;使用高位数的深度缓冲区。

1.深度测试

//演示OpenGL背面剔除、深度测试、多边形模型
#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLGeometryTransform.h"
#include <math.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

GLFrame viewFrame; //设置角色帧,作为相机
GLFrustum viewFrustum; //使用此类设置透视投影
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;

//标记背面剔除、深度测试
int iCull = 0;
int iDepth = 0;


//开始渲染
void renderScene(void) {
    //1.清除窗口和深度缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //可以注掉看看效果
    
    //开启关闭正背面剔除功能
    if (iCull) {
        glEnable(GL_CULL_FACE);
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
    }
    else {
        glDisable(GL_CULL_FACE);
    }
    
    //根据设置iDepth标记来判断是否开启深度测试
    if (iDepth) {
        glEnable(GL_DEPTH_TEST);
    }
    else {
        glDisable(GL_DEPTH_TEST);
    }
    
    //2.把摄像机矩阵压入模型矩阵中
    //    modelViewMatrix.PushMatrix(viewFrame);
    //或者
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);

    M3DMatrix44f mObjectFrame;
    viewFrame.GetMatrix(mObjectFrame);
    modelViewMatrix.MultMatrix(mObjectFrame);
    //3.设置绘图颜色
    GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
    /*4.使用默认光源着色器通过光源阴影效果体现立体效果
     参数1 GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
     参数2 模型视图矩阵
     参数3 投影矩阵
     参数4 基本颜色值
     */
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
    //5.绘制
    torusBatch.Draw();
    //6.出栈 绘制完成恢复
    modelViewMatrix.PopMatrix();
    //7.交换缓冲区
    glutSwapBuffers();
    
}

//为程序做一次性的设置
void setupRC() {
    //1.设置背景色
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    //2.初始化着色器管理器
    shaderManager.InitializeStockShaders();
    //3.将相机后移7个单位
    viewFrame.MoveForward(7.0);
    //4.创建一个甜甜圈
    /*
     参数1:容器帮助类
     参数2:外边缘半径
     参数3:内边缘半径
     参数4、5:主半径和从半径的细分单元数量
     */
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    //5.点的大小(方便点填充时,肉眼观察)
    glPointSize(4.0f);
}

//通过camera即viewFrame的移动从而改变视口
void specialKeys(int key, int x, int y) {
    //1.判断方向
    if (key == GLUT_KEY_UP) {
        //2.根据方向调整观察者位置
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
    }
    if (key == GLUT_KEY_DOWN) {
        viewFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
    }
    if (key == GLUT_KEY_LEFT) {
        viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
    }
    if (key == GLUT_KEY_RIGHT) {
        viewFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
    }
    //3.重新刷新
    glutPostRedisplay();
}

//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
    //1.防止h变为0
    if (h == 0) {
        h = 1;
    }
    //2.设置视口窗口尺寸
    glViewport(0, 0, w, h);
    //3.SetPerspective函数的参数是一个从顶点方向看上去的视场角度,用角度值表示
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);
    //4.把透视矩阵加载到透视矩阵堆栈中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //5.初始化渲染管线
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    
}

void processMenu(int value) {
    switch (value) {
        case 1:
            iDepth = !iDepth;
            break;
        case 2:
            iCull = !iCull;
            break;
        case 3:
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            break;
        case 4:
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            break;
        case 5:
            glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
            break;
    }
    glutPostRedisplay();
}


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);
    
    //添加右击菜单栏
    glutCreateMenu(processMenu);
    glutAddMenuEntry("Toggle depth test", 1);
    glutAddMenuEntry("Toggle cull backface", 2);
    glutAddMenuEntry("Set Fill Mode", 3);
    glutAddMenuEntry("Set Line Mode", 4);
    glutAddMenuEntry("Set Point Mode", 5);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
        return 1;
    }
    setupRC();
    glutMainLoop();
    
    return 0;
}

2.OpenGL 裁剪

#include "GLTools.h"

#ifdef __APPLE__
#include <GLUT/GLUT.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

//开始渲染
void renderScene(void) {
    //设置清屏颜色为蓝色
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 1.裁剪一个红色的小矩形
    //(1)设置裁剪区颜色为红色
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    //(2)设置裁剪尺寸
    glScissor(100, 100, 600, 400);
    //(3)开启裁剪测试
    glEnable(GL_SCISSOR_TEST);
    //(4)开启清屏,执行裁剪
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 2.裁剪一个绿色的小矩形
    //(1)设置裁剪区颜色为绿色
    glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
    //(2)设置裁剪尺寸
    glScissor(200, 200, 400, 200);
    //(3)开启清屏,执行裁剪
    glClear(GL_COLOR_BUFFER_BIT);
    
    //关闭裁剪测试
    glDisable(GL_SCISSOR_TEST);
    //强制执行缓存区
    glutSwapBuffers();
    
}

//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
    if (h == 0) {
        h = 1;
    }
    glViewport(0, 0, w, h);
}

int main(int argc, char *argv[]) {

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 800);
    glutCreateWindow("OpenGL Scissor");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(renderScene);
    glutMainLoop();
    
    return 0;
}

3.OpenGL混合

#include "GLShaderManager.h"
#include "GLTools.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
};


//为程序做一次性的设置
void setupRC() {
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    shaderManager.InitializeStockShaders();
    //绘制一个移动矩形
    squareBatch.Begin(GL_TRIANGLE_FAN, 4);
    squareBatch.CopyVertexData3f(vVerts);
    squareBatch.End();
    
    //绘制4个固定矩形
    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();
    
    
}

void specialKeys(int key, int x, int y) {
    GLfloat stepSize = 0.025f;
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[7];
    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;
    }

    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;
    }
    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();
}

//开始渲染
void renderScene(void) {
    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 };
    
    //将4个固定矩形绘制好
    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 glBlendFunc glDisable注释掉后就就不会混合了,可以注释掉看效果
    //1.开启混合
    glEnable(GL_BLEND);
    //2.开启组合函数,计算混合颜色因子
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //3.使用着色器管理
    //参数1 使用单位着色器  参数2 着色器颜色
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    //4.容器类开始绘制
    squareBatch.Draw();
    //5.关闭混合
    glDisable(GL_BLEND);
    //同步绘制命令
    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(800, 600);
    glutCreateWindow("移动矩形,观察颜色");
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "Error:%s\n",glewGetErrorString(err));
        return 1;
    }
    
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(renderScene);
    glutSpecialFunc(specialKeys);
    setupRC();
    glutMainLoop();
    
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读