/* could rv3d->persmat */ void BLI_uvproject_from_view(float target[2], float source[3], float persmat[4][4], float rotmat[4][4], float winx, float winy) { float pv4[4], x = 0.0, y = 0.0; copy_v3_v3(pv4, source); pv4[3] = 1.0; /* rotmat is the object matrix in this case */ mul_m4_v4(rotmat, pv4); /* almost ED_view3d_project_short */ mul_m4_v4(persmat, pv4); if (fabsf(pv4[3]) > 0.00001f) { /* avoid division by zero */ target[0] = winx / 2.0f + (winx / 2.0f) * pv4[0] / pv4[3]; target[1] = winy / 2.0f + (winy / 2.0f) * pv4[1] / pv4[3]; } else { /* scaling is lost but give a valid result */ target[0] = winx / 2.0f + (winx / 2.0f) * pv4[0]; target[1] = winy / 2.0f + (winy / 2.0f) * pv4[1]; } /* v3d->persmat seems to do this funky scaling */ if (winx > winy) { y = (winx - winy) / 2.0f; winy = winx; } else { x = (winy - winx) / 2.0f; winx = winy; } target[0] = (x + target[0]) / winx; target[1] = (y + target[1]) / winy; }
void BLI_uvproject_from_camera(float target[2], float source[3], ProjCameraInfo *uci) { float pv4[4]; copy_v3_v3(pv4, source); pv4[3] = 1.0; /* rotmat is the object matrix in this case */ if (uci->do_rotmat) mul_m4_v4(uci->rotmat, pv4); /* caminv is the inverse camera matrix */ mul_m4_v4(uci->caminv, pv4); if (uci->do_pano) { float angle = atan2f(pv4[0], -pv4[2]) / ((float)M_PI * 2.0f); /* angle around the camera */ if (uci->do_persp == FALSE) { target[0] = angle; /* no correct method here, just map to 0-1 */ target[1] = pv4[1] / uci->camsize; } else { float vec2d[2]; /* 2D position from the camera */ vec2d[0] = pv4[0]; vec2d[1] = pv4[2]; target[0] = angle * ((float)M_PI / uci->camangle); target[1] = pv4[1] / (len_v2(vec2d) * (uci->camsize * 2.0f)); } } else { if (pv4[2] == 0.0f) pv4[2] = 0.00001f; /* don't allow div by 0 */ if (uci->do_persp == FALSE) { target[0] = (pv4[0] / uci->camsize); target[1] = (pv4[1] / uci->camsize); } else { target[0] = (-pv4[0] * ((1.0f / uci->camsize) / pv4[2])) / 2.0f; target[1] = (-pv4[1] * ((1.0f / uci->camsize) / pv4[2])) / 2.0f; } } target[0] *= uci->xasp; target[1] *= uci->yasp; /* adds camera shift + 0.5 */ target[0] += uci->shiftx; target[1] += uci->shifty; }
static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) { int a, flag = -1, fl; for (a = 0; a < 8; a++) { float vec[4], min, max; copy_v3_v3(vec, bb->vec[a]); vec[3] = 1.0; mul_m4_v4(persmatob, vec); max = vec[3]; min = -vec[3]; fl = 0; if (vec[0] < min) fl += 1; if (vec[0] > max) fl += 2; if (vec[1] < min) fl += 4; if (vec[1] > max) fl += 8; if (vec[2] < min) fl += 16; if (vec[2] > max) fl += 32; flag &= fl; if (flag == 0) return true; } return false; }
static void imapaint_project(float matrix[4][4], const float co[3], float pco[4]) { copy_v3_v3(pco, co); pco[3] = 1.0f; mul_m4_v4(matrix, pco); }
void project_short_noclip(ARegion *ar, const float vec[3], short adr[2]) { RegionView3D *rv3d= ar->regiondata; float fx, fy, vec4[4]; copy_v3_v3(vec4, vec); vec4[3]= 1.0; adr[0]= IS_CLIPPED; mul_m4_v4(rv3d->persmat, vec4); if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); if( fx>-32700 && fx<32700) { fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); if(fy > -32700.0f && fy < 32700.0f) { adr[0]= (short)floor(fx); adr[1]= (short)floor(fy); } } } }
void project_short(ARegion *ar, const float vec[3], short adr[2]) /* clips */ { RegionView3D *rv3d= ar->regiondata; float fx, fy, vec4[4]; adr[0]= IS_CLIPPED; if(rv3d->rflag & RV3D_CLIPPING) { if(ED_view3d_test_clipping(rv3d, vec, 0)) return; } copy_v3_v3(vec4, vec); vec4[3]= 1.0; mul_m4_v4(rv3d->persmat, vec4); if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); if( fx>0 && fx<ar->winx) { fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); if(fy > 0.0f && fy < (float)ar->winy) { adr[0]= (short)floor(fx); adr[1]= (short)floor(fy); } } } }
int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb) { /* return 1: draw */ float mat[4][4]; float vec[4], min, max; int a, flag= -1, fl; if(bb==NULL) return 1; if(bb->flag & OB_BB_DISABLED) return 1; mult_m4_m4m4(mat, rv3d->persmat, obmat); for(a=0; a<8; a++) { copy_v3_v3(vec, bb->vec[a]); vec[3]= 1.0; mul_m4_v4(mat, vec); max= vec[3]; min= -vec[3]; fl= 0; if(vec[0] < min) fl+= 1; if(vec[0] > max) fl+= 2; if(vec[1] < min) fl+= 4; if(vec[1] > max) fl+= 8; if(vec[2] < min) fl+= 16; if(vec[2] > max) fl+= 32; flag &= fl; if(flag==0) return 1; } return 0; }
/* create intersection coordinates in view Z direction at mouse coordinates */ void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) { RegionView3D *rv3d= ar->regiondata; if(rv3d->is_persp) { float vec[3]; ED_view3d_win_to_vector(ar, mval, vec); copy_v3_v3(ray_start, rv3d->viewinv[3]); madd_v3_v3v3fl(ray_start, rv3d->viewinv[3], vec, v3d->near); madd_v3_v3v3fl(ray_end, rv3d->viewinv[3], vec, v3d->far); } else { float vec[4]; vec[0] = 2.0f * mval[0] / ar->winx - 1; vec[1] = 2.0f * mval[1] / ar->winy - 1; vec[2] = 0.0f; vec[3] = 1.0f; mul_m4_v4(rv3d->persinv, vec); madd_v3_v3v3fl(ray_start, vec, rv3d->viewinv[2], 1000.0f); madd_v3_v3v3fl(ray_end, vec, rv3d->viewinv[2], -1000.0f); } /* clipping */ if(rv3d->rflag & RV3D_CLIPPING) { int a; for(a=0; a<4; a++) { clip_line_plane(ray_start, ray_end, rv3d->clip[a]); } } }
void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) { RegionView3D *rv3d = ar->regiondata; if (rv3d->is_persp) { float vec[3]; ED_view3d_win_to_vector(ar, mval, vec); copy_v3_v3(ray_start, rv3d->viewinv[3]); madd_v3_v3v3fl(ray_start, rv3d->viewinv[3], vec, v3d->near); madd_v3_v3v3fl(ray_end, rv3d->viewinv[3], vec, v3d->far); } else { float vec[4]; vec[0] = 2.0f * mval[0] / ar->winx - 1; vec[1] = 2.0f * mval[1] / ar->winy - 1; vec[2] = 0.0f; vec[3] = 1.0f; mul_m4_v4(rv3d->persinv, vec); madd_v3_v3v3fl(ray_start, vec, rv3d->viewinv[2], 1000.0f); madd_v3_v3v3fl(ray_end, vec, rv3d->viewinv[2], -1000.0f); } }
static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco) { VECCOPY(pco, co); pco[3]= 1.0f; mul_m4_v3(ob->obmat, pco); mul_m4_v3((float(*)[4])model, pco); mul_m4_v4((float(*)[4])proj, pco); }
/* perspmat is typically... * - 'rv3d->perspmat', is_local == false * - 'rv3d->persmatob', is_local == true */ static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar, float perspmat[4][4], const bool is_local, /* normally hidden */ const float co[3], float r_co[2], const eV3DProjTest flag) { float vec4[4]; /* check for bad flags */ BLI_assert((flag & V3D_PROJ_TEST_ALL) == flag); if (flag & V3D_PROJ_TEST_CLIP_BB) { RegionView3D *rv3d = ar->regiondata; if (rv3d->rflag & RV3D_CLIPPING) { if (ED_view3d_clipping_test(rv3d, co, is_local)) { return V3D_PROJ_RET_CLIP_BB; } } } copy_v3_v3(vec4, co); vec4[3] = 1.0; mul_m4_v4(perspmat, vec4); if (((flag & V3D_PROJ_TEST_CLIP_ZERO) == 0) || (fabsf(vec4[3]) > (float)BL_ZERO_CLIP)) { if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) { const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]) : 0.0f; const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar)); if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) { const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar)); if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) { r_co[0] = fx; r_co[1] = fy; /* check if the point is behind the view, we need to flip in this case */ if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) { negate_v2(r_co); } } else { return V3D_PROJ_RET_CLIP_WIN; } } else { return V3D_PROJ_RET_CLIP_WIN; } } else { return V3D_PROJ_RET_CLIP_NEAR; } } else { return V3D_PROJ_RET_CLIP_ZERO; } return V3D_PROJ_RET_OK; }
static void imapaint_project(Object *ob, float model[4][4], float proj[4][4], const float co[3], float pco[4]) { copy_v3_v3(pco, co); pco[3] = 1.0f; mul_m4_v3(ob->obmat, pco); mul_m4_v3(model, pco); mul_m4_v4(proj, pco); }
/** * Calculate a normalized 3d direction vector from the viewpoint towards a global location. * In orthographic view the resulting vector will match the view vector. * \param rv3d The region (used for the window width and height). * \param coord The world-space location. * \param vec The resulting normalized vector. */ void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3]) { if (rv3d->is_persp) { float p1[4], p2[4]; copy_v3_v3(p1, coord); p1[3] = 1.0f; copy_v3_v3(p2, p1); p2[3] = 1.0f; mul_m4_v4((float (*)[4])rv3d->viewmat, p2); mul_v3_fl(p2, 2.0f); mul_m4_v4((float (*)[4])rv3d->viewinv, p2); sub_v3_v3v3(vec, p1, p2); } else { copy_v3_v3(vec, rv3d->viewinv[2]); } normalize_v3(vec); }
static void camera_frame_fit_data_init( const Scene *scene, const Object *ob, CameraParams *params, CameraViewFrameData *data) { float camera_rotmat_transposed_inversed[4][4]; unsigned int i; /* setup parameters */ BKE_camera_params_init(params); BKE_camera_params_from_object(params, ob); /* compute matrix, viewplane, .. */ if (scene) { BKE_camera_params_compute_viewplane(params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); } else { BKE_camera_params_compute_viewplane(params, 1, 1, 1.0f, 1.0f); } BKE_camera_params_compute_matrix(params); /* initialize callback data */ copy_m3_m4(data->camera_rotmat, (float (*)[4])ob->obmat); normalize_m3(data->camera_rotmat); /* To transform a plane which is in its homogeneous representation (4d vector), * we need the inverse of the transpose of the transform matrix... */ copy_m4_m3(camera_rotmat_transposed_inversed, data->camera_rotmat); transpose_m4(camera_rotmat_transposed_inversed); invert_m4(camera_rotmat_transposed_inversed); /* Extract frustum planes from projection matrix. */ planes_from_projmat(params->winmat, /* left right top bottom near far */ data->plane_tx[2], data->plane_tx[0], data->plane_tx[3], data->plane_tx[1], NULL, NULL); /* Rotate planes and get normals from them */ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { mul_m4_v4(camera_rotmat_transposed_inversed, data->plane_tx[i]); normalize_v3_v3(data->normal_tx[i], data->plane_tx[i]); } copy_v4_fl(data->dist_vals_sq, FLT_MAX); data->tot = 0; data->is_ortho = params->is_ortho; if (params->is_ortho) { /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ negate_v3_v3(data->camera_no, data->camera_rotmat[2]); data->dist_to_cam = FLT_MAX; } }
void apply_project_float(float persmat[4][4], int winx, int winy, const float vec[3], float adr[2]) { float vec4[4]; copy_v3_v3(vec4, vec); vec4[3]= 1.0; adr[0]= IS_CLIPPED; mul_m4_v4(persmat, vec4); if(vec4[3] > (float)BL_NEAR_CLIP) { adr[0] = (float)(winx/2.0f)+(winx/2.0f)*vec4[0]/vec4[3]; adr[1] = (float)(winy/2.0f)+(winy/2.0f)*vec4[1]/vec4[3]; } }
void project_float(ARegion *ar, const float vec[3], float adr[2]) { RegionView3D *rv3d= ar->regiondata; float vec4[4]; adr[0]= IS_CLIPPED; copy_v3_v3(vec4, vec); vec4[3]= 1.0; mul_m4_v4(rv3d->persmat, vec4); if(vec4[3] > (float)BL_NEAR_CLIP) { adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; } }
/* use view3d_get_object_project_mat to get projecting mat */ void ED_view3d_project_float(const ARegion *ar, const float vec[3], float adr[2], float mat[4][4]) { float vec4[4]; adr[0]= IS_CLIPPED; copy_v3_v3(vec4, vec); vec4[3]= 1.0; mul_m4_v4(mat, vec4); if( vec4[3]>FLT_EPSILON ) { adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; } else { adr[0] = adr[1] = 0.0f; } }
/** * \note use #ED_view3d_ob_project_mat_get to get the projection matrix */ void ED_view3d_project_float_v2_m4(const ARegion *ar, const float co[3], float r_co[2], float mat[4][4]) { float vec4[4]; copy_v3_v3(vec4, co); vec4[3] = 1.0; /* r_co[0] = IS_CLIPPED; */ /* always overwritten */ mul_m4_v4(mat, vec4); if (vec4[3] > FLT_EPSILON) { r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3]; r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3]; } else { zero_v2(r_co); } }
void project_int_noclip(ARegion *ar, const float vec[3], int adr[2]) { RegionView3D *rv3d= ar->regiondata; float fx, fy, vec4[4]; copy_v3_v3(vec4, vec); vec4[3]= 1.0; mul_m4_v4(rv3d->persmat, vec4); if( fabs(vec4[3]) > BL_NEAR_CLIP ) { fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]); fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]); adr[0] = (int)floor(fx); adr[1] = (int)floor(fy); } else { adr[0] = ar->winx / 2; adr[1] = ar->winy / 2; } }
bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs) { GPUTexture *src, *target; int numslots = 0; float invproj[4][4]; int i; /* number of passes left. when there are no more passes, the result is passed to the frambuffer */ int passes_left = fx->num_passes; /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */ float viewvecs[3][4] = { {-1.0f, -1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f, 1.0f} }; if (fx->effects == 0) return false; /* first, unbind the render-to-texture framebuffer */ GPU_framebuffer_texture_detach(fx->color_buffer); GPU_framebuffer_texture_detach(fx->depth_buffer); if (fx->restore_stencil) glPopAttrib(); src = fx->color_buffer; target = fx->color_buffer_sec; /* set up quad buffer */ glVertexPointer(2, GL_FLOAT, 0, fullscreencos); glTexCoordPointer(2, GL_FLOAT, 0, fullscreenuvs); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); /* full screen FX pass */ /* invert the view matrix */ invert_m4_m4(invproj, projmat); /* convert the view vectors to view space */ for (i = 0; i < 3; i++) { mul_m4_v4(invproj, viewvecs[i]); /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); if (is_persp) mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); viewvecs[i][3] = 1.0; } /* we need to store the differences */ viewvecs[1][0] -= viewvecs[0][0]; viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1]; /* calculate a depth offset as well */ if (!is_persp) { float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; mul_m4_v4(invproj, vec_far); mul_v3_fl(vec_far, 1.0f / vec_far[3]); viewvecs[1][2] = vec_far[2] - viewvecs[0][2]; } /* set invalid color in case shader fails */ glColor3f(1.0, 0.0, 1.0); glDisable(GL_DEPTH_TEST); /* ssao pass */ if (fx->effects & GPU_FX_FLAG_SSAO) { GPUShader *ssao_shader; ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp); if (ssao_shader) { const GPUSSAOSettings *fx_ssao = fx->settings.ssao; int color_uniform, depth_uniform; int ssao_uniform, ssao_color_uniform, viewvecs_uniform, ssao_sample_params_uniform; int ssao_jitter_uniform, ssao_concentric_tex; float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f}; float sample_params[4]; sample_params[0] = fx->ssao_sample_count; /* multiplier so we tile the random texture on screen */ sample_params[2] = fx->gbuffer_dim[0] / 64.0; sample_params[3] = fx->gbuffer_dim[1] / 64.0; ssao_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_params"); ssao_color_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_color"); color_uniform = GPU_shader_get_uniform(ssao_shader, "colorbuffer"); depth_uniform = GPU_shader_get_uniform(ssao_shader, "depthbuffer"); viewvecs_uniform = GPU_shader_get_uniform(ssao_shader, "viewvecs"); ssao_sample_params_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_sample_params"); ssao_concentric_tex = GPU_shader_get_uniform(ssao_shader, "ssao_concentric_tex"); ssao_jitter_uniform = GPU_shader_get_uniform(ssao_shader, "jitter_tex"); GPU_shader_bind(ssao_shader); GPU_shader_uniform_vector(ssao_shader, ssao_uniform, 4, 1, ssao_params); GPU_shader_uniform_vector(ssao_shader, ssao_color_uniform, 4, 1, fx_ssao->color); GPU_shader_uniform_vector(ssao_shader, viewvecs_uniform, 4, 3, viewvecs[0]); GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 4, 1, sample_params); GPU_texture_bind(src, numslots++); GPU_shader_uniform_texture(ssao_shader, color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); GPU_depth_texture_mode(fx->depth_buffer, false, true); GPU_shader_uniform_texture(ssao_shader, depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->jitter_buffer, numslots++); GPU_shader_uniform_texture(ssao_shader, ssao_jitter_uniform, fx->jitter_buffer); GPU_texture_bind(fx->ssao_concentric_samples_tex, numslots++); GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_concentric_samples_tex); /* draw */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(src); GPU_depth_texture_mode(fx->depth_buffer, true, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->jitter_buffer); GPU_texture_unbind(fx->ssao_concentric_samples_tex); /* may not be attached, in that case this just returns */ if (target) { GPU_framebuffer_texture_detach(target); if (ofs) { GPU_offscreen_bind(ofs, false); } else { GPU_framebuffer_restore(); } } /* swap here, after src/target have been unbound */ SWAP(GPUTexture *, target, src); numslots = 0; } } /* second pass, dof */ if (fx->effects & GPU_FX_FLAG_DOF) { const GPUDOFSettings *fx_dof = fx->settings.dof; GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5; float dof_params[4]; float scale = scene->unit.system ? scene->unit.scale_length : 1.0f; /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though * because the shader reads coordinates in world space, which is in blender units. */ float scale_camera = 0.001f / scale; /* we want radius here for the aperture number */ float aperture = 0.5f * scale_camera * fx_dof->focal_length / fx_dof->fstop; dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length)); dof_params[1] = fx_dof->focus_distance / scale; dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); dof_params[3] = 0.0f; /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */ dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp); dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp); dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp); dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp); dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp); /* error occured, restore framebuffers and return */ if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) { GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); GPU_framebuffer_restore(); return false; } /* pass first, first level of blur in low res buffer */ { int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; int viewvecs_uniform; float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer"); depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); GPU_shader_bind(dof_shader_pass1); GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(src, numslots++); GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); GPU_depth_texture_mode(fx->depth_buffer, false, true); GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); /* target is the downsampled coc buffer */ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); /* binding takes care of setting the viewport to the downsampled size */ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(src); GPU_depth_texture_mode(fx->depth_buffer, true, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); numslots = 0; } /* second pass, gaussian blur the downsampled image */ { int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; int viewvecs_uniform; float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; float tmp = invrendertargetdim[0]; invrendertargetdim[0] = 0.0f; dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params"); invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim"); color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer"); depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer"); viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs"); /* Blurring vertically */ GPU_shader_bind(dof_shader_pass2); GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(fx->depth_buffer, numslots++); GPU_depth_texture_mode(fx->depth_buffer, false, true); GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer); /* use final buffer as a temp here */ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); /* Drawing quad */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* *unbind/detach */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); /* Blurring horizontally */ invrendertargetdim[0] = tmp; invrendertargetdim[1] = 0.0f; GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer); GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* *unbind/detach */ GPU_depth_texture_mode(fx->depth_buffer, true, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->dof_near_coc_final_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer); dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); numslots = 0; } /* third pass, calculate near coc */ { int near_coc_downsampled, near_coc_blurred; near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer"); near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer"); GPU_shader_bind(dof_shader_pass3); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer); GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer); GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); /* unbinding here restores the size to the original */ GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); numslots = 0; } /* fourth pass blur final coc once to eliminate discontinuities */ { int near_coc_downsampled; int invrendertargetdim_uniform; float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer"); invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim"); GPU_shader_bind(dof_shader_pass4); GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer); GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_final_buffer); /* unbinding here restores the size to the original */ GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); numslots = 0; } /* final pass, merge blurred layers according to final calculated coc */ { int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform; int invrendertargetdim_uniform, viewvecs_uniform; float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer"); high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer"); dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params"); invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim"); original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer"); depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer"); viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs"); GPU_shader_bind(dof_shader_pass5); GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(src, numslots++); GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src); GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer); GPU_texture_bind(fx->depth_buffer, numslots++); GPU_depth_texture_mode(fx->depth_buffer, false, true); GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer); /* if this is the last pass, prepare for rendering on the frambuffer */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); GPU_texture_unbind(src); GPU_depth_texture_mode(fx->depth_buffer, true, false); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ if (target) { GPU_framebuffer_texture_detach(target); if (ofs) { GPU_offscreen_bind(ofs, false); } else { GPU_framebuffer_restore(); } } SWAP(GPUTexture *, target, src); numslots = 0; } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); GPU_shader_unbind(); return true; }