アキュムレーションバッファ

accumulation-buffer.png
OpenGL3以降非推奨になりましたフレームバッファオブジェクトで代用可能です
被写界深度なし 被写界深度あり
withoutdof.png accumulation-buffer.png

視点を少しずつずらしたfrustumを加算してぼかす手法で被写界深度を表現する

jitter.h
#include <stdlib.h>
#include <math.h>
#include <GLFW/glfw3.h>
#include <GL/freeglut.h>
#include "jitter.h"
#define PI_ 3.14159265358979323846
GLuint teapotList;
/* accFrustum()
* 最初の6つの引数はglFrustum()を呼ぶ時のものと同じです。
*
* pixdx と pixdy は各ピクセルにおけるアンチエイリアスの揺らぎです
* 両方0にするとno anti-alias jitter.
* eyedx と eyedy は各ピクセルにおける被写界深度の揺らぎです
* 両方0にすると被写界深度エフェクトがなくなります。
*
* focus は視点から焦点平面までの距離です。
* focus は0以上かつ、0と等しくあってはいけません。つまりfocus>0
*
* 注:accFrustum() は glTranslatef()を呼んでいます.
* なので、accFrustum()を呼ぶ前はモデルビュー行列を恒等行列で初期化したほうがよいでしょう。
*/
void accFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar,
    GLdouble pixdx, GLdouble pixdy, GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
    GLdouble xwsize, ywsize;
    GLdouble dx, dy;
    GLint viewport[4];
 
    glGetIntegerv(GL_VIEWPORT, viewport);
 
    xwsize = right - left;
    ywsize = top - bottom;
 
    dx = -(pixdx*xwsize / (GLdouble)viewport[2] + eyedx*zNear / focus);
    dy = -(pixdy*ywsize / (GLdouble)viewport[3] + eyedy*zNear / focus);
 
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(left + dx, right + dx, bottom + dy, top + dy, zNear, zFar);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-eyedx, -eyedy, 0.0);
}
 
/*  accPerspective()
*
*  最初の4つの引数はgluPerspective()を呼ぶときと一緒です。
* pixdx と pixdy は各ピクセルにおけるアンチエイリアスの揺らぎです
* 両方0にするとno anti-alias jitter.
* eyedx と eyedy は各ピクセルにおける被写界深度の揺らぎです
* 両方0にすると被写界深度エフェクトがなくなります。
*
* focus は視点から焦点平面までの距離です。
* focus は0以上かつ、0と等しくあってはいけません。つまりfocus>0
 
*
*  注:accPerspective() は内部で accFrustum()を呼んでいます
*/
void accPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar,
    GLdouble pixdx, GLdouble pixdy, GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
    GLdouble fov2, left, right, bottom, top;
 
    fov2 = ((fovy*PI_) / 180.0) / 2.0;
 
    top = zNear / (cos(fov2) / sin(fov2));
    bottom = -top;
 
    right = top * aspect;
    left = -right;
 
    accFrustum(left, right, bottom, top, zNear, zFar, pixdx, pixdy, eyedx, eyedy, focus);
}
 
void init(void)
{
    GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 };
 
    GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    GLfloat local_view[] = { 0.0 };
 
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
 
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
 
    glFrontFace(GL_CW);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glEnable(GL_DEPTH_TEST);
 
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearAccum(0.0, 0.0, 0.0, 0.0);
    /*  make teapot display list */
    teapotList = glGenLists(1);
    glNewList(teapotList, GL_COMPILE);
    glutSolidTeapot(0.5);
    glEndList();
}
 
void renderTeapot(GLfloat x, GLfloat y, GLfloat z, GLfloat ambr, GLfloat ambg, GLfloat ambb, GLfloat difr, GLfloat difg, GLfloat difb, GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine)
{
    GLfloat mat[4];
 
    glPushMatrix();
    glTranslatef(x, y, z);
    mat[0] = ambr; mat[1] = ambg; mat[2] = ambb; mat[3] = 1.0;
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
    mat[0] = difr; mat[1] = difg; mat[2] = difb;
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
    mat[0] = specr; mat[1] = specg; mat[2] = specb;
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat);
    glMaterialf(GL_FRONT, GL_SHININESS, shine*128.0);
    glCallList(teapotList);
    glPopMatrix();
}
 
/*  display() 関数では5個のユタティーポットをアキュムレーションバッファに何回か描きます。
*  アキュムレーションバッファに描く毎に少しずらした視錘台で描画します。
*  焦点は z = 5.0です。なので金色のティーポットに焦点が合った状態になります。
*  揺らぎの度合いはaccPerspective() jitterの倍率によって調整されます。この例では0.33にしてあります。
*  このサンプルでは各ティーポットは8回描画されます。
*/
void display(GLFWwindow* window)
{
    float ratio;
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    ratio = width / (float)height;
    glViewport(0, 0, width, height);
 
    int jitter;
    GLint viewport[4];
 
    glGetIntegerv(GL_VIEWPORT, viewport);
    glClear(GL_ACCUM_BUFFER_BIT);
    glClearColor(0.3, 0.3, 0.3,1.0);
 
    for (jitter = 0; jitter < 8; jitter++) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
        accPerspective(45.0, (GLdouble)viewport[2] / (GLdouble)viewport[3], 1.0, 15.0, 0.0, 0.0, 0.33*j8[jitter].x, 0.33*j8[jitter].y, 5.0);
 
        /*    ruby, gold, silver, emerald, and cyan teapots    */
        renderTeapot(-1.1f, -0.5f, -4.5f,
            0.1745f, 0.01175f,
            0.01175f, 0.61424f, 0.04136f, 0.04136f,
            0.727811f, 0.626959f, 0.626959f, 0.6f);
        renderTeapot(-0.5, -0.5, -5.0,
            0.24725, 0.1995,
            0.0745, 0.75164, 0.60648, 0.22648,
            0.628281, 0.555802, 0.366065, 0.4);
        renderTeapot(0.2, -0.5, -5.5,
            0.19225, 0.19225,
            0.19225, 0.50754, 0.50754, 0.50754,
            0.508273, 0.508273, 0.508273, 0.4);
        renderTeapot(1.0, -0.5, -6.0,
            0.0215, 0.1745, 0.0215,
            0.07568, 0.61424, 0.07568, 0.633,
            0.727811, 0.633, 0.6);
        renderTeapot(1.8, -0.5, -6.5,
            0.0, 0.1, 0.06, 0.0,
            0.50980392, 0.50980392, 0.50196078,
            0.50196078, 0.50196078, .25);
        glAccum(GL_ACCUM, 0.125);
    }
    glAccum(GL_RETURN, 1.0);
    glFlush();
}
 
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}
 
void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case 27:
        exit(0);
        break;
    }
}
 
/*  メインループ
*   accumulation bufferを忘れずにリクエストすること
*/
int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glfwInit();
 
    GLFWwindow* window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    glfwWindowHint(GLFW_ACCUM_RED_BITS, 8);
    glfwWindowHint(GLFW_ACCUM_GREEN_BITS, 8);
    glfwWindowHint(GLFW_ACCUM_BLUE_BITS, 8);
    glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, 8);
 
    glfwMakeContextCurrent(window);
    init();
    while (!glfwWindowShouldClose(window))
    {
        display(window);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
 
    glfwTerminate();
    return 0;
}

depth-of-field opengl-deprecated

サポートサイト Wikidot.com depth-of-fieldopengl-deprecated