X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Feffects%2Fambientocclusion.cpp;h=a407c2d9918621b3aa9f057fd93597845635f1e9;hb=7f81f26889b84542b0b35685b0e80383256cdc47;hp=e5de04b4846eebf5fe5ff24569e637f1760ce4ee;hpb=9a63244c1342337915c4610401a24c09fa72cc3d;p=libs%2Fgl.git diff --git a/source/effects/ambientocclusion.cpp b/source/effects/ambientocclusion.cpp index e5de04b4..a407c2d9 100644 --- a/source/effects/ambientocclusion.cpp +++ b/source/effects/ambientocclusion.cpp @@ -12,22 +12,39 @@ using namespace std; namespace Msp { namespace GL { -AmbientOcclusion::AmbientOcclusion(Resources &resources, unsigned w, unsigned h, float): +AmbientOcclusion::AmbientOcclusion(unsigned w, unsigned h, float): + rotate_lookup(get_or_create_rotate_lookup()), occlude_target(w, h, (RENDER_COLOR,R8)), - occlude_shader(resources.get("_ambientocclusion_occlude.glsl")), - combine_shader(resources.get("_ambientocclusion_combine.glsl")), - quad(resources.get("_fullscreen_quad.mesh")), - linear_sampler(resources.get("_linear_clamp.samp")), - nearest_sampler(resources.get("_nearest_clamp.samp")) + occlude_shader(Resources::get_global().get("_ambientocclusion_occlude.glsl.shader")), + combine_shader(Resources::get_global().get("_ambientocclusion_combine.glsl.shader")), + quad(Resources::get_global().get("_fullscreen_quad.mesh")), + linear_sampler(Resources::get_global().get("_linear_clamp.samp")), + nearest_clamp_sampler(Resources::get_global().get("_nearest_clamp.samp")), + nearest_sampler(Resources::get_global().get("_nearest.samp")) { - texturing.attach(2, occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler); + set_n_samples(16); + set_occlusion_radius(0.5f); + set_darkness(1.0f); + set_edge_depth_threshold(0.1f); +} + +const Texture2D &AmbientOcclusion::get_or_create_rotate_lookup() +{ + Resources &resources = Resources::get_global(); + + static const string name = "_ambientocclusion_rotate.tex2d"; + Texture2D *rotate_lookup = resources.find(name); + if(rotate_lookup) + return *rotate_lookup; + + rotate_lookup = new Texture2D; + rotate_lookup->storage(RGBA8, 4, 4, 1); + resources.add(name, rotate_lookup); - unsigned seed = 1; - rotate_lookup.storage(RGBA8, 4, 4, 1); unsigned char data[64]; for(unsigned i=0; i<16; ++i) { - Geometry::Angle a = Geometry::Angle::from_turns(random(seed)); + Geometry::Angle a = Geometry::Angle::from_turns(i*7/16.0f); unsigned char c = (cos(a)*0.5f+0.5f)*255; unsigned char s = (sin(a)*0.5f+0.5f)*255; data[i*4 ] = c; @@ -35,27 +52,17 @@ AmbientOcclusion::AmbientOcclusion(Resources &resources, unsigned w, unsigned h, data[i*4+2] = 255-s; data[i*4+3] = ((i+i/4)%2)*255; } - rotate_lookup.image(0, data); + rotate_lookup->image(0, data); - texturing.attach(3, rotate_lookup, &nearest_sampler); - - shdata.uniform("source", 0); - shdata.uniform("depth", 1); - shdata.uniform("occlusion", 2); - shdata.uniform("rotate", 3); - shdata.uniform("inverse_projection", Matrix()); - - set_n_samples(16); - set_occlusion_radius(0.5f); - set_darkness(1.0f); - set_edge_depth_threshold(0.1f); + return *rotate_lookup; } -float AmbientOcclusion::random(unsigned &seed) +float AmbientOcclusion::radical_inverse(unsigned n) { - static const unsigned modulus = (1U<<31)-1; - seed = (static_cast(seed)*48271)%modulus; // minstd - return static_cast(seed)/(modulus-1); + unsigned inv = ((n&0x55)<<1) | ((n&0xAA)>>1); + inv = ((inv&0x33)<<2) | ((inv&0xCC)>>2); + inv = ((inv&0x0F)<<4) | ((inv&0xF0)>>4); + return inv/256.0f; } void AmbientOcclusion::set_n_samples(unsigned n) @@ -63,13 +70,14 @@ void AmbientOcclusion::set_n_samples(unsigned n) if(n<1 || n>32) throw out_of_range("AmbientOcclusion::set_n_samples"); - unsigned seed = 1; - float radius_divisor = (n-1)*(n-1); Vector3 sample_points[32]; for(unsigned i=0; i(i)/n; + float r = sqrt(1.0f-z*z); + float d = radical_inverse(i); + Geometry::Angle a = Geometry::Angle::from_turns(d); + sample_points[i] = Vector3(cos(a)*r, sin(a)*r, z)*(0.1f+0.9f*d*d); } shdata.uniform3_array("sample_points", n, &sample_points[0].x); shdata.uniform("n_samples", static_cast(n)); @@ -92,14 +100,11 @@ void AmbientOcclusion::set_edge_depth_threshold(float edt) void AmbientOcclusion::render(Renderer &renderer, const Texture2D &color, const Texture2D &depth) { - texturing.attach(0, color, &nearest_sampler); - texturing.attach(1, depth, &nearest_sampler); - - if(renderer.get_camera()) - shdata.uniform("inverse_projection", invert(renderer.get_camera()->get_projection_matrix())); - Renderer::Push push(renderer); - renderer.set_texturing(&texturing); + renderer.set_texture("source", &color, &nearest_clamp_sampler); + renderer.set_texture("depth", &depth, &nearest_clamp_sampler); + renderer.set_texture("occlusion", &occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler); + renderer.set_texture("rotate", &rotate_lookup, &nearest_sampler); renderer.set_shader_program(&occlude_shader, &shdata); { @@ -119,9 +124,9 @@ AmbientOcclusion::Template::Template(): edge_depth_threshold(0.1f) { } -AmbientOcclusion *AmbientOcclusion::Template::create(Resources &res, unsigned width, unsigned height) const +AmbientOcclusion *AmbientOcclusion::Template::create(unsigned width, unsigned height) const { - RefPtr ao = new AmbientOcclusion(res, width/size_divisor, height/size_divisor); + RefPtr ao = new AmbientOcclusion(width/size_divisor, height/size_divisor); ao->set_n_samples(n_samples); ao->set_occlusion_radius(occlusion_radius); ao->set_darkness(darkness);