《OpenGL 超级宝典(Super Bible)第五版》 有关 PBO 的 Example

简介: 《OpenGL 超级宝典(Super Bible)第五版》 有关 PBO 的 Example

代码即关键注释如下:

static GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
GLsizei  screenWidth;     // Desired window or desktop width
GLsizei  screenHeight;      // Desired window or desktop height
GLboolean bFullScreen;      // Request to run full screen
GLboolean bAnimated;      // Request for continual updates
GLShaderManager   shaderManager;      // Shader Manager
GLMatrixStack       modelViewMatrix;    // Modelview Matrix
GLMatrixStack       projectionMatrix;   // Projection Matrix
M3DMatrix44f        orthoMatrix;
GLFrustum         viewFrustum;        // View Frustum
GLGeometryTransform transformPipeline;    // Geometry Transform Pipeline
GLFrame           cameraFrame;        // Camera frame
GLTriangleBatch     torusBatch;
GLBatch           floorBatch;
GLBatch           screenQuad;
GLuint              textures[1];
GLuint              blurTextures[6];
GLuint              pixBuffObjs[1];
GLuint              curBlurTarget;
bool                bUsePBOPath;
GLfloat             speedFactor;
GLuint              blurProg;
void                *pixelData;
GLuint              pixelDataSize;
//void MoveCamera(void);
void DrawWorld(GLfloat yRot, GLfloat xPos);
bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode);
void SetupBlurProg(void);
// returns 1 - 6 for blur texture units
// curPixBuf is always between 0 and 5
void AdvanceBlurTaget()
{
    curBlurTarget = ((curBlurTarget + 1) % 6);
}
GLuint GetBlurTarget0()
{
    return (1 + ((curBlurTarget + 5) % 6));
}
GLuint GetBlurTarget1()
{
    return (1 + ((curBlurTarget + 4) % 6));
}
GLuint GetBlurTarget2()
{
    return (1 + ((curBlurTarget + 3) % 6));
}
GLuint GetBlurTarget3()
{
    return (1 + ((curBlurTarget + 2) % 6));
}
GLuint GetBlurTarget4()
{
    return (1 + ((curBlurTarget + 1) % 6));
}
GLuint GetBlurTarget5()
{
    return (1 + ((curBlurTarget) % 6));
}
void UpdateFrameCount()
{
    static int iFrames = 0;           // Frame count
    static CStopWatch frameTimer;     // Render time
    // Reset the stopwatch on first time
    if(iFrames == 0)
    {
        frameTimer.Reset();
        iFrames++;
    }
    // Increment the frame count
    iFrames++;
    // Do periodic frame rate calculation
    if (iFrames == 101)
    {
        float fps;
        fps = 100.0f / frameTimer.GetElapsedSeconds();
        if (bUsePBOPath)
            printf("Pix_buffs - Using PBOs  %.1f fps\n", fps);
        else
            printf("Pix_buffs - Using Client mem copies %.1f fps\n", fps);
        frameTimer.Reset();
        iFrames = 1;
    }
}
///
// Load in a BMP file as a texture. Allows specification of the filters and the wrap mode
bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    GLbyte *pBits;
    GLint iWidth, iHeight;
    pBits = gltReadBMPBits(szFileName, &iWidth, &iHeight);
    if(pBits == NULL)
        return false;
    // Set Wrap modes
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
    // Do I need to generate mipmaps?
    if(minFilter == GL_LINEAR_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_NEAREST_MIPMAP_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, pBits);
    return true;
}
///
// OpenGL related startup code is safe to put here. Load textures, etc.
void SetupRC(void)
{
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }
    // Initialze Shader Manager
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    // Black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 35, 35);
    GLfloat alpha = 0.25f;
    floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
    floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
    floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    floorBatch.Normal3f(0.0, 1.0f, 0.0f);
    floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f);
    floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
    floorBatch.MultiTexCoord2f(0, 10.0f, 0.0f);
    floorBatch.Normal3f(0.0, 1.0f, 0.0f);
    floorBatch.Vertex3f(20.0f, -0.41f, 20.0f);
    floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
    floorBatch.MultiTexCoord2f(0, 10.0f, 10.0f);
    floorBatch.Normal3f(0.0, 1.0f, 0.0f);
    floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
    floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
    floorBatch.MultiTexCoord2f(0, 0.0f, 10.0f);
    floorBatch.Normal3f(0.0, 1.0f, 0.0f);
    floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
    floorBatch.End();
    glGenTextures(1, textures);
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    LoadBMPTexture("marble.bmp", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
    // Create blur program
    blurProg =  gltLoadShaderPairWithAttributes("blur.vs", "blur.fs", 2,
                GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "texCoord0");
    // Create blur textures
    glGenTextures(6, blurTextures);
  // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
    // XXX I don't think this is necessary. Should set texture data to NULL
    // Allocate a pixel buffer to initialize textures and PBOs
  // 计算 像素数据的字节数
    pixelDataSize = screenWidth * screenHeight * 3 * sizeof(unsigned int); // XXX This should be unsigned byte
  // 可以直接用 NULL 初始化 Texture
    //void *data = (void *)malloc(pixelDataSize);
    //memset(data, 0x00, pixelDataSize);
    // Setup 6 texture units for blur effect
    // Initialize texture data
    for (int i = 0; i < 6; i++)
    {
        glActiveTexture(GL_TEXTURE1 + i);
        glBindTexture(GL_TEXTURE_2D, blurTextures[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL/*data*/);
    }
    // Alloc space for copying pixels so we dont call malloc on every draw
  // 创建分配 PBO,并绑定为Pack Buffer,类型为GL_DYNAMIC_COPY
    glGenBuffers(1, pixBuffObjs);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
    glBufferData(GL_PIXEL_PACK_BUFFER, pixelDataSize, pixelData, GL_DYNAMIC_COPY);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
  // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
    // Create geometry and a matrix for screen aligned drawing
    gltGenerateOrtho2DMat(screenWidth, screenHeight, orthoMatrix, screenQuad);
    // Make sure all went well
    gltCheckErrors();
}
///
// Do your cleanup here. Free textures, display lists, buffer objects, etc.
void ShutdownRC(void)
{
    // Make sure default FBO is bound
  // 确保绑定默认的 FBO
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
    // Cleanup textures
    for (int i = 0; i < 7; i++)
    {
        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, 0);
    }
    // Now delete detached textures
    glDeleteTextures(1, textures);
    glDeleteTextures(6, blurTextures);
    // delete PBO
  // ☆ 删除 PBO
    glDeleteBuffers(1, pixBuffObjs);
}
///
// This is called at least once and before any rendering occurs. If the screen
// is a resizeable window, then this will also get called whenever the window
// is resized.
void ChangeSize(int nWidth, int nHeight)
{
    glViewport(0, 0, nWidth, nHeight);
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    modelViewMatrix.LoadIdentity();
    // update screen sizes
    screenWidth = nWidth;
    screenHeight = nHeight;
    // reset screen aligned quad
    gltGenerateOrtho2DMat(screenWidth, screenHeight, orthoMatrix, screenQuad);
  // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
    free(pixelData);
    pixelDataSize = screenWidth * screenHeight * 3 * sizeof(unsigned int);
    pixelData = (void *)malloc(pixelDataSize);
    //  Resize PBOs
  // 如果窗口大小发生变化,则重新分配 PBO
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
    glBufferData(GL_PIXEL_PACK_BUFFER, pixelDataSize, pixelData, GL_DYNAMIC_COPY);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
  // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
    gltCheckErrors();
}
///
// Update the camera based on user input, toggle display modes
//
void ProccessKeys(unsigned char key, int x, int y)
{
    static CStopWatch cameraTimer;
    float fTime = cameraTimer.GetElapsedSeconds();
    float linear = fTime * 12.0f;
    cameraTimer.Reset();
    // Alternate between PBOs and local memory when 'P' is pressed
  // 按 P键 切换 PBO和内存
    if(key == 'P' || key == 'p')
        bUsePBOPath = (bUsePBOPath) ? GL_FALSE : GL_TRUE;
    // Speed up movement
    if(key == '+')
    {
        speedFactor += linear / 2;
        if(speedFactor > 6)
            speedFactor = 6;
    }
    // Slow down moement
    if(key == '-')
    {
        speedFactor -= linear / 2;
        if(speedFactor < 0.5)
            speedFactor = 0.5;
    }
}
///
// Load and setup program for blur effect
//
void SetupBlurProg(void)
{
    // Set the blur program as the current one
    glUseProgram(blurProg);
    // Set MVP matrix
    glUniformMatrix4fv(glGetUniformLocation(blurProg, "mvpMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
    // Setup the textue units for the blur targets, these rotate every frame
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit0"), GetBlurTarget0());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit1"), GetBlurTarget1());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit2"), GetBlurTarget2());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit3"), GetBlurTarget3());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit4"), GetBlurTarget4());
    glUniform1i(glGetUniformLocation(blurProg, "textureUnit5"), GetBlurTarget5());
}
///
// Draw the scene
//
void DrawWorld(GLfloat yRot, GLfloat xPos)
{
    M3DMatrix44f mCamera;
    modelViewMatrix.GetMatrix(mCamera);
    // Need light position relative to the Camera
    M3DVector4f vLightTransformed;
    m3dTransformVector4(vLightTransformed, vLightPos, mCamera);
    // Draw stuff relative to the camera
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
    modelViewMatrix.Translate(xPos, 0.0f, 0.0f);
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,
                                 modelViewMatrix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightTransformed, vGreen, 0);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix();
}
///
// Render a frame. The owning framework is responsible for buffer swaps,
// flushes, etc.
void RenderScene(void)
{
    static CStopWatch animationTimer;
    static float totalTime = 6; // To go back and forth
    static float halfTotalTime = totalTime / 2;
    float seconds = animationTimer.GetElapsedSeconds() * speedFactor;
    float xPos = 0;
    // Calculate the next postion of the moving object
    // First perform a mod-like operation on the time as a float
    while(seconds > totalTime)
        seconds -= totalTime;
    // Move object position, if it's gone half way across
    // start bringing it back
    if(seconds < halfTotalTime)
        xPos = seconds - halfTotalTime * 0.5f;
    else
        xPos = totalTime - seconds - halfTotalTime * 0.5f;
    // First draw world to screen
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[0]); // Marble
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0);
    floorBatch.Draw();
    DrawWorld(0.0f, xPos);
    modelViewMatrix.PopMatrix();
    if(bUsePBOPath)
    {
        // First bind the PBO as the pack buffer, then read the pixels directly to the PBO
    // ☆ 首先绑定 PBO 为 Pack Buffer,再直接从 Frame Buffer 中读取像素到 PBO ☆ 
        glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
        glReadPixels(0, 0, screenWidth, screenHeight, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);  // 解绑 PBO
        // Next bind the PBO as the unpack buffer, then push the pixels straight into the texture
    // ☆  接着绑定 PBO 为 Unpack Buffer,再把 PBO 中的像素直接推送到纹理当中 ☆ 
        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixBuffObjs[0]);
        // Setup texture unit for new blur, this gets imcremented every frame
        glActiveTexture(GL_TEXTURE0 + GetBlurTarget0() );
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);  // 解绑 PBO
    }
    else
    {
        // Grab the screen pixels and copy into local memory
    // 从FrameBuffer中获取屏幕像素,并拷贝到客户端内存中
        glReadPixels(0, 0, screenWidth, screenHeight, GL_RGB, GL_UNSIGNED_BYTE, pixelData);
        // Push pixels from client memory into texture
        // Setup texture unit for new blur, this gets imcremented every frame
    // 推送客户端内存中的像素到纹理中
        glActiveTexture(GL_TEXTURE0 + GetBlurTarget0() );
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pixelData);
    }
    // Draw full screen quad with blur shader and all blur textures
    projectionMatrix.PushMatrix();
    projectionMatrix.LoadIdentity();
    projectionMatrix.LoadMatrix(orthoMatrix);
    modelViewMatrix.PushMatrix();
    modelViewMatrix.LoadIdentity();
    glDisable(GL_DEPTH_TEST);
    SetupBlurProg();
    screenQuad.Draw();
    glEnable(GL_DEPTH_TEST);
    modelViewMatrix.PopMatrix();
    projectionMatrix.PopMatrix();
    // Move to the next blur texture for the next frame
    AdvanceBlurTaget();
    // Do the buffer Swap
    glutSwapBuffers();
    // Do it again
    glutPostRedisplay();
    UpdateFrameCount();
}
int main(int argc, char *argv[])
{
    screenWidth  = 800;
    screenHeight = 600;
    bFullScreen = false;
    bAnimated   = true;
    bUsePBOPath = false;  // true
    blurProg    = 0;
    speedFactor = 1.0f;
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(screenWidth, screenHeight);
    glutCreateWindow("Pix Buffs");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutKeyboardFunc(ProccessKeys);
    SetupRC();
    glutMainLoop();
    ShutdownRC();
    return 0;
}

执行效果图:

image.png

相关阅读:OpenGL深入探索——像素缓冲区对象 (PBO)


目录
相关文章
|
Android开发 数据安全/隐私保护 C++
Opengl ES之PBO
Opengl ES连载系列
141 0
|
并行计算
《OpenGL 超级宝典(Super Bible)第七版》 有关 PBO 的 Example
《OpenGL 超级宝典(Super Bible)第七版》 有关 PBO 的 Example
293 0
《OpenGL 超级宝典(Super Bible)第七版》 有关 PBO 的 Example
|
存储 缓存 异构计算
NDK OpenGL ES 3.0 开发(二十二):PBO
OpenGL PBO(Pixel Buffer Object),被称为像素缓冲区对象,主要被用于异步像素传输操作。PBO 仅用于执行像素传输,不连接到纹理,且与 FBO (帧缓冲区对象)无关。
529 0
NDK OpenGL ES 3.0 开发(二十二):PBO
|
存储 openCL C++
A Simple OpenGL Shader Example II
A Simple OpenGL Shader Example II eryar@163.com Abstract. The OpenGL Shading Language syntax comes from the C family of programming languages.
1220 0
|
缓存 程序员 异构计算
A Simple OpenGL Shader Example
A Simple OpenGL Shader Example eryar@163.com Abstract. OpenGL Shading Language, the high-level programming language defined to allow application writ...
1540 0
|
5月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
55 0
|
存储 编解码 算法
Opengl ES之LUT滤镜(上)
Opengl ES之连载系列
343 0
|
数据安全/隐私保护 开发者
OpenGL ES 多目标渲染(MRT)
Opengl ES连载系列
221 0
|
数据安全/隐私保护 索引
Opengl ES之纹理数组
Opengl ES连载系列
176 0
|
数据安全/隐私保护
Opengl ES之水印贴图
Opengl ES之连载系列
88 0