void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) { float scaleh[2] = {1.0f/GPU_texture_opengl_width(blurtex), 0.0f}; float scalev[2] = {0.0f, 1.0f/GPU_texture_opengl_height(tex)}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); int scale_uniform, texture_source_uniform; if (!blur_shader) return; scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU"); texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource"); /* Blurring horizontally */ /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid * pushing unnecessary matrices onto the OpenGL stack. */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); GPU_shader_bind(blur_shader); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scaleh); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex)); /* Peparing to draw quad */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GPU_texture_bind(tex, 0); /* Drawing quad */ glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex2f(1, 1); glTexCoord2d(1, 0); glVertex2f(-1, 1); glTexCoord2d(1, 1); glVertex2f(-1, -1); glTexCoord2d(0, 1); glVertex2f(1, -1); glEnd(); /* Blurring vertically */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex)); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scalev); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); GPU_texture_bind(blurtex, 0); glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex2f(1, 1); glTexCoord2d(1, 0); glVertex2f(-1, 1); glTexCoord2d(1, 1); glVertex2f(-1, -1); glTexCoord2d(0, 1); glVertex2f(1, -1); glEnd(); GPU_shader_unbind(); }
static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec, bool use_fire, const float min[3], const float ob_sizei[3], const float invsize[3]) { int invsize_location = GPU_shader_get_uniform(shader, "invsize"); int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); int min_location = GPU_shader_get_uniform(shader, "min_location"); int soot_location; int stepsize_location; int densityscale_location; int spec_location, flame_location; int shadow_location, actcol_location; if (use_fire) { spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); flame_location = GPU_shader_get_uniform(shader, "flame_texture"); } else { shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); actcol_location = GPU_shader_get_uniform(shader, "active_color"); soot_location = GPU_shader_get_uniform(shader, "soot_texture"); stepsize_location = GPU_shader_get_uniform(shader, "step_size"); densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); } GPU_shader_bind(shader); if (use_fire) { GPU_texture_bind(sds->tex_flame, 2); GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); GPU_texture_bind(tex_spec, 3); GPU_shader_uniform_texture(shader, spec_location, tex_spec); } else { float density_scale = 10.0f; GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); GPU_texture_bind(sds->tex, 0); GPU_shader_uniform_texture(shader, soot_location, sds->tex); GPU_texture_bind(sds->tex_shadow, 1); GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); float active_color[3] = { 0.9, 0.9, 0.9 }; if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) mul_v3_v3(active_color, sds->active_color); GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); } GPU_shader_uniform_vector(shader, min_location, 3, 1, min); GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); }
static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) { GPUShader *shader = pass->shader; GPUNode *node; GPUInput *next, *input; ListBase *inputs = &pass->inputs; int extract, z; memset(inputs, 0, sizeof(*inputs)); if (!shader) return; GPU_shader_bind(shader); for (node = nodes->first; node; node = node->next) { z = 0; for (input = node->inputs.first; input; input = next, z++) { next = input->next; /* attributes don't need to be bound, they already have * an id that the drawing functions will use */ if (input->source == GPU_SOURCE_ATTRIB || input->source == GPU_SOURCE_BUILTIN || input->source == GPU_SOURCE_OPENGL_BUILTIN) { continue; } if (input->ima || input->tex || input->prv) BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); else BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); /* pass non-dynamic uniforms to opengl */ extract = 0; if (input->ima || input->tex || input->prv) { if (input->bindtex) extract = 1; } else if (input->dynamicvec) extract = 1; if (extract) input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); /* extract nodes */ if (extract) { BLI_remlink(&node->inputs, input); BLI_addtail(inputs, input); } } } GPU_shader_unbind(); }
void GPU_fx_compositor_XRay_resolve(GPUFX *fx) { GPUShader *depth_resolve_shader; GPU_framebuffer_texture_detach(fx->depth_buffer_xray); /* attach regular framebuffer */ GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL); /* full screen quad where we will always write to depth buffer */ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT); glDepthFunc(GL_ALWAYS); /* disable scissor from sculpt if any */ glDisable(GL_SCISSOR_TEST); /* disable writing to color buffer, it's depth only pass */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* set up quad buffer */ glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); glVertexPointer(2, GL_FLOAT, 0, NULL); glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float))); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); depth_resolve_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_RESOLVE, false); if (depth_resolve_shader) { int depth_uniform; depth_uniform = GPU_shader_get_uniform(depth_resolve_shader, "depthbuffer"); GPU_shader_bind(depth_resolve_shader); GPU_texture_bind(fx->depth_buffer_xray, 0); GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); GPU_shader_uniform_texture(depth_resolve_shader, depth_uniform, fx->depth_buffer_xray); /* draw */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); GPU_texture_unbind(fx->depth_buffer_xray); GPU_shader_unbind(); } glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glPopAttrib(); }
static GPUShader *gpu_simple_shader(int options) { /* glsl code */ extern char datatoc_gpu_shader_simple_vert_glsl[]; extern char datatoc_gpu_shader_simple_frag_glsl[]; GPUShader *shader; /* detect if we can do faster lighting for solid draw mode */ if (options & GPU_SHADER_LIGHTING) if (solid_compatible_lighting()) options |= GPU_SHADER_SOLID_LIGHTING; /* cached shaders */ shader = GPU_MATERIAL_STATE.cached_shaders[options]; if (!shader && !GPU_MATERIAL_STATE.failed_shaders[options]) { /* create shader if it doesn't exist yet */ char defines[64*GPU_SHADER_OPTIONS_NUM] = ""; if (options & GPU_SHADER_OVERRIDE_DIFFUSE) strcat(defines, "#define USE_COLOR\n"); if (options & GPU_SHADER_TWO_SIDED) strcat(defines, "#define USE_TWO_SIDED\n"); if (options & GPU_SHADER_TEXTURE_2D) strcat(defines, "#define USE_TEXTURE\n"); if (options & GPU_SHADER_SOLID_LIGHTING) strcat(defines, "#define USE_SOLID_LIGHTING\n"); else if (options & GPU_SHADER_LIGHTING) strcat(defines, "#define USE_SCENE_LIGHTING\n"); shader = GPU_shader_create( datatoc_gpu_shader_simple_vert_glsl, datatoc_gpu_shader_simple_frag_glsl, NULL, NULL, defines, 0, 0, 0); if (shader) { /* set texture map to first texture unit */ if (options & GPU_SHADER_TEXTURE_2D) glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0); GPU_MATERIAL_STATE.cached_shaders[options] = shader; } else GPU_MATERIAL_STATE.failed_shaders[options] = true; } return shader; }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const float min[3], const float max[3], const float viewnormal[3]) { if (!sds->tex || !sds->tex_shadow) { fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n"); return; } const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; GPUShader *shader = GPU_shader_get_builtin_shader( (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); return; } const float ob_sizei[3] = { 1.0f / fabsf(ob->size[0]), 1.0f / fabsf(ob->size[1]), 1.0f / fabsf(ob->size[2]) }; const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] }; const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] }; #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* setup smoke shader */ int soot_location = GPU_shader_get_uniform(shader, "soot_texture"); int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); int flame_location = GPU_shader_get_uniform(shader, "flame_texture"); int actcol_location = GPU_shader_get_uniform(shader, "active_color"); int stepsize_location = GPU_shader_get_uniform(shader, "step_size"); int densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); int invsize_location = GPU_shader_get_uniform(shader, "invsize"); int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); int min_location = GPU_shader_get_uniform(shader, "min"); GPU_shader_bind(shader); GPU_texture_bind(sds->tex, 0); GPU_shader_uniform_texture(shader, soot_location, sds->tex); GPU_texture_bind(sds->tex_shadow, 1); GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); GPUTexture *tex_spec = NULL; if (use_fire) { GPU_texture_bind(sds->tex_flame, 2); GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); tex_spec = create_flame_spectrum_texture(); GPU_texture_bind(tex_spec, 3); GPU_shader_uniform_texture(shader, spec_location, tex_spec); } float active_color[3] = { 0.9, 0.9, 0.9 }; float density_scale = 10.0f; if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) mul_v3_v3(active_color, sds->active_color); GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); GPU_shader_uniform_vector(shader, min_location, 3, 1, min); GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); /* setup slicing information */ const int max_slices = 256; const int max_points = max_slices * 12; VolumeSlicer slicer; copy_v3_v3(slicer.min, min); copy_v3_v3(slicer.max, max); copy_v3_v3(slicer.size, size); slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices"); const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); /* setup buffer and draw */ int gl_depth = 0, gl_blend = 0; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, NULL); glDrawArrays(GL_TRIANGLES, 0, num_points); glDisableClientState(GL_VERTEX_ARRAY); #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif /* cleanup */ glBindBuffer(GL_ARRAY_BUFFER, 0); glDeleteBuffers(1, &vertex_buffer); GPU_texture_unbind(sds->tex); GPU_texture_unbind(sds->tex_shadow); if (use_fire) { GPU_texture_unbind(sds->tex_flame); GPU_texture_unbind(tex_spec); GPU_texture_free(tex_spec); } MEM_freeN(slicer.verts); GPU_shader_unbind(); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); } }
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; }