《OpenGL ES 2.0 Programming Guide》第12章“最简单的FBO Depth Texture”示例代码【C语言版】

简介: 《OpenGL ES 2.0 Programming Guide》第12章“最简单的FBO Depth Texture”示例代码【C语言版】

由于《OpenGL ES 2.0 Programming Guide》原书并没有提供第12章的示例代码,书上的代码也只提到关键的步骤,而网上大多是Android/iOS版本的示例,C/C++的大都基于OpenGL或OpenGL ES 3.0,为了加深理解,遂自己实现了一份C语言版本的,希望能够帮助到同样喜欢OpenGL ES 2.0的同学。

废话不多说,直接上代码:

#include <stdlib.h>
#include <stdio.h>
#include "esUtil.h"
#define SIZE 512
typedef struct 
{
  GLuint programFBOObject;
  GLuint programObject;
  GLuint frameBuffer;
  GLuint texture;
  GLuint depthTexture;
  GLint positionFBOLoc;
  GLint mvpFBOLoc;
  GLint positionLoc;
  GLint mvpLoc;
  GLint texcoordLoc;
  GLint samplerLoc;
  GLfloat *vertices;
  GLfloat *texcoords;
  GLuint *indices;
  int numIndices;
  GLfloat angle;
  ESMatrix mvpMatrix;
} UserData;
int initFBO(ESContext *esContext, GLint width, GLint height)
{
  GLenum status;
  //GLint maxRenderbufferSize;
  UserData *userData = (UserData *)esContext->userData;
  //glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderbufferSize);
   check if GL_MAX_RENDERBUFFER_SIZE is >= texWidth and texHeight
  //if ((maxRenderbufferSize <= width) || (maxRenderbufferSize <= height))
  //{
  //  // cannot use framebuffer objects as we need to create
  //  // a depth buffer as a renderbuffer object
  //  printf("Cannot use framebuffer objects!\n");
  //  exit(EXIT_FAILURE);
  //  return FALSE;
  //}
  // generate the framebuffer
  glGenFramebuffers(1, &userData->frameBuffer);
  // Depth Texture
  glGenTextures(1, &userData->depthTexture);
  glBindTexture(GL_TEXTURE_2D, userData->depthTexture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 
    0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  // Color Texture
  glGenTextures(1, &userData->texture);
  glBindTexture(GL_TEXTURE_2D, userData->texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, 
    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  // bind the framebuffer
  glBindFramebuffer(GL_FRAMEBUFFER, userData->frameBuffer);
  // specify texture as color attachment 
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, userData->texture, 0);
  // ☆specify depth_texture as depth attachment
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, userData->depthTexture, 0);
  // check for framebuffer complete
  status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if (status != GL_FRAMEBUFFER_COMPLETE)
  {
    printf("Framebuffer object is not complete!\n");
    exit(EXIT_FAILURE);
    return FALSE;
  }
  //glBindFramebuffer(GL_FRAMEBUFFER, 0);
  return TRUE;
}
int InitFBOShader(ESContext *esContext)
{
  UserData *userData = (UserData *)esContext->userData;
  const char vShaderStr[] =
    "uniform mat4 u_mvpMatrix;                   \n"
    "attribute vec4 a_position;                  \n"
    "void main()                                 \n"
    "{                                           \n"
    "   gl_Position = u_mvpMatrix * a_position;  \n"
    "}                                           \n";
  const char fShaderStr[] =
    "precision mediump float;                            \n"
    "void main()                                         \n"
    "{                                                   \n"
    "  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);          \n"
    "}                                                   \n";
  userData->programFBOObject = esLoadProgram(vShaderStr, fShaderStr);
  if (!userData->programFBOObject) 
    return FALSE;
  // Bind vPosition to attribute 0   
  //glBindAttribLocation(userData->programFBOObject, 0, "a_position");
  userData->positionFBOLoc = glGetAttribLocation ( userData->programFBOObject, "a_position" );
  userData->mvpFBOLoc = glGetUniformLocation( userData->programFBOObject, "u_mvpMatrix" );
  return TRUE;
}
int initShader(ESContext *esContext)
{
  UserData *userData = (UserData *)esContext->userData;
  const char vShaderStr[] =  
    "uniform mat4 u_mvpMatrix;                   \n"
    "attribute vec4 a_position;                  \n"
    "attribute vec2 a_texCoord;                  \n"
    "varying vec2 v_texCoord;                    \n"
    "void main()                                 \n"
    "{                                           \n"
    "   gl_Position = u_mvpMatrix * a_position;  \n"
    "   v_texCoord = a_texCoord;                 \n"
    "}                                           \n";
  const char fShaderStr[] =  
    "precision mediump float;                            \n"
    "varying vec2 v_texCoord;                            \n"
    "uniform sampler2D s_texture;                        \n"
    "void main()                                         \n"
    "{                                                   \n"
    "  vec4 color = texture2D(s_texture, v_texCoord);    \n"
    "  gl_FragColor = color;                             \n"
    "}                                                   \n";
  // Load the shaders and get a linked program object
  userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
  // Get the attribute locations
  userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
  // Get the uniform locations
  userData->mvpLoc = glGetUniformLocation( userData->programObject, "u_mvpMatrix" );
  // Get the texture  attribute locations
  userData->texcoordLoc = glGetAttribLocation(userData->programObject, "a_texCoord");
  userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");
  return TRUE;
}
int Init(ESContext *esContext)
{
  UserData *userData = (UserData *)esContext->userData;
  if (!InitFBOShader(esContext))
  {
    printf("initFBOShader exception ! \n");
    return FALSE;
  }
  if (!initShader(esContext))
  {
    printf("initShader exception ! \n");
    return FALSE;
  }
  initFBO(esContext, SIZE, SIZE);
  // Generate the vertex data
  userData->numIndices = esGenCube( 1.0, &userData->vertices,
    NULL, &userData->texcoords, &userData->indices );
  // Starting rotation angle for the cube
  userData->angle = 45.0f;
  glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
  glClearDepthf( 1.0f );
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
  return TRUE;
}
// Update the mvp matrix
void Update(ESContext *esContext, float deltaTime)
{
  UserData *userData = (UserData*) esContext->userData;
  ESMatrix perspective;
  ESMatrix modelview;
  float    aspect;
  // Compute a rotation angle based on time to rotate the cube
  userData->angle += ( deltaTime * 40.0f );
  if( userData->angle >= 360.0f )
    userData->angle -= 360.0f;
  // Compute the window aspect ratio
  aspect = (GLfloat) esContext->width / (GLfloat) esContext->height;
  // Generate a perspective matrix with a 60 degree FOV
  esMatrixLoadIdentity( &perspective );
  esPerspective( &perspective, 60.0f, aspect, 1.0f, 20.0f );
  // Generate a model view matrix to rotate/translate the cube
  esMatrixLoadIdentity( &modelview );
  // Translate away from the viewer
  esTranslate( &modelview, 0.0, 0.0, -2.0 );
  // Rotate the cube
  esRotate( &modelview, userData->angle, 1.0, 0.0, 1.0 );
  // Compute the final MVP by multiplying the 
  // modevleiw and perspective matrices together
  esMatrixMultiply( &userData->mvpMatrix, &modelview, &perspective );
}
void DrawToFBO(ESContext *esContext)
{
  UserData *userData = (UserData *)esContext->userData;
  glBindFramebuffer(GL_FRAMEBUFFER, userData->frameBuffer);
  // Set the viewport
  glViewport ( 0, 0, esContext->width, esContext->height );
  // Clear the color buffer
  glClearColor ( 1.0f, 1.0f, 1.0f, 1.0f );
  glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  // Use the program object
  glUseProgram ( userData->programFBOObject );
  // -----------------------------------------------------------
  // Load the vertex position
  glVertexAttribPointer ( userData->positionFBOLoc, 3, GL_FLOAT, 
    GL_FALSE, 3 * sizeof(GLfloat), userData->vertices );
  glEnableVertexAttribArray ( userData->positionFBOLoc );
  // -----------------------------------------------------------
  // Load the MVP matrix
  glUniformMatrix4fv( userData->mvpFBOLoc, 1, GL_FALSE, 
    (GLfloat*) &userData->mvpMatrix.m[0][0] );
  // -----------------------------------------------------------
  // Draw the cube
  glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices );
}
void Draw(ESContext *esContext)
{
  UserData *userData = (UserData *)esContext->userData;
  DrawToFBO(esContext);
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  // Set the viewport
  glViewport ( 0, 0, esContext->width, esContext->height );
  // Clear the color buffer
  glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
  glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  // Use the program object
  glUseProgram ( userData->programObject );
  // -----------------------------------------------------------
  // Load the vertex position
  glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT, 
    GL_FALSE, 3 * sizeof(GLfloat), userData->vertices );
  glEnableVertexAttribArray ( userData->positionLoc );
  // -----------------------------------------------------------
  // Load the texture coordinate
  glVertexAttribPointer(userData->texcoordLoc, 2, GL_FLOAT,
    GL_FALSE, 2 * sizeof(GLfloat), userData->texcoords);
  glEnableVertexAttribArray(userData->texcoordLoc);
  // -----------------------------------------------------------
  // Load the MVP matrix
  glUniformMatrix4fv( userData->mvpLoc, 1, GL_FALSE, 
    (GLfloat*) &userData->mvpMatrix.m[0][0] );
  // -----------------------------------------------------------
  // Bind the texture unit 0
  // Set the sampler texture unit to 0
  glActiveTexture(GL_TEXTURE0);
  // Bind a texturing target.While a texture is bound, GL operations on th    
  // -e target to which it is bound affect the bound texture, and queries                                                 
  // of the target to which it is bound return state from the bound texture
  //glBindTexture(GL_TEXTURE_2D, userData->texture);
  glBindTexture(GL_TEXTURE_2D, userData->depthTexture); // ☆
  glUniform1i(userData->samplerLoc, 0);
  // -----------------------------------------------------------
  // Draw the cube
  glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices );
  eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
  glBindTexture(GL_TEXTURE_2D, 0);
}
void ShutDown(ESContext *esContext)
{
  UserData *userData = (UserData *)esContext->userData;
  if ( userData->vertices != NULL )
  {
    free ( userData->vertices );
  }
  if ( userData->texcoords != NULL )
  {
    free ( userData->texcoords );
  }
  if ( userData->indices != NULL )
  {
    free ( userData->indices );
  }
  // Delete program object
  glDeleteProgram (userData->programObject);
  glDeleteProgram(userData->programFBOObject);
  // Delete texture
  glDeleteTextures(1, &userData->texture);
  glDeleteTextures(1, &userData->depthTexture);
  glDeleteFramebuffers(1, &userData->frameBuffer);
}
int main ( int argc, char *argv[] )
{
  ESContext esContext;
  UserData  userData;
  esInitContext ( &esContext );
  esContext.userData = &userData;
  esCreateWindow ( &esContext, "Simple FBO", SIZE, SIZE, ES_WINDOW_RGB );
  if ( !Init ( &esContext ) )
    return 0;
  esRegisterDrawFunc ( &esContext, Draw );
  esRegisterUpdateFunc ( &esContext, Update );
  esMainLoop ( &esContext );
  ShutDown ( &esContext );
}

效果图:

image.png

目录
相关文章
ly~
|
1月前
|
数据可视化 BI API
除了 OpenGL,还有哪些常用的图形库可以在 C 语言中使用?
除了OpenGL,C语言中还有多个常用的图形库:SDL,适合初学者,用于2D游戏和多媒体应用;Allegro,高性能,支持2D/3D图形,广泛应用于游戏开发;Cairo,矢量图形库,支持高质量图形输出,适用于数据可视化;SFML,提供简单接口,用于2D/3D游戏及多媒体应用;GTK+,开源窗口工具包,用于创建图形用户界面。这些库各有特色,适用于不同的开发需求。
ly~
184 4
|
6月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
126 0
|
缓存 C++
Opengl ES之FBO
Opengl ES连载系列
153 0
|
存储 编解码 算法
Opengl ES之LUT滤镜(上)
Opengl ES之连载系列
460 0
|
数据安全/隐私保护 开发者
OpenGL ES 多目标渲染(MRT)
Opengl ES连载系列
323 0
|
数据安全/隐私保护 索引
Opengl ES之纹理数组
Opengl ES连载系列
259 0
|
数据安全/隐私保护
Opengl ES之水印贴图
Opengl ES之连载系列
152 0
|
Java 数据安全/隐私保护 Android开发
Opengl ES之矩阵变换(下)
Opengl ES连载系列
132 0
|
Java API 数据安全/隐私保护
Opengl ES之矩阵变换(上)
Opengl ES连载系列
149 0
|
存储
Opengl ES之踩坑记
Opengl ES之连载系列
137 0