GLColorBuffer GLCameraBlurFilter::Filter(GLColorBuffer input, float radialBlur) { SPADES_MARK_FUNCTION(); if(radialBlur > 0.f) radialBlur = 1.f - radialBlur; else radialBlur = 1.f; bool hasRadialBlur = radialBlur < .9999f; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); dev->Enable(IGLDevice::Blend, false); static GLProgramAttribute programPosition("positionAttribute"); static GLProgramUniform programTexture("texture"); static GLProgramUniform programDepthTexture("depthTexture"); static GLProgramUniform programReverseMatrix("reverseMatrix"); static GLProgramUniform programShutterTimeScale("shutterTimeScale"); programPosition(program); programTexture(program); programDepthTexture(program); programReverseMatrix(program); programShutterTimeScale(program); const client::SceneDefinition& def = renderer->GetSceneDef(); Matrix4 newMatrix = Matrix4::Identity(); newMatrix.m[0] = def.viewAxis[0].x; newMatrix.m[1] = def.viewAxis[1].x; newMatrix.m[2] = def.viewAxis[2].x; newMatrix.m[4] = def.viewAxis[0].y; newMatrix.m[5] = def.viewAxis[1].y; newMatrix.m[6] = def.viewAxis[2].y; newMatrix.m[8] = def.viewAxis[0].z; newMatrix.m[9] = def.viewAxis[1].z; newMatrix.m[10] = def.viewAxis[2].z; // othrogonal matrix can be reversed fast Matrix4 inverseNewMatrix = newMatrix.Transposed(); Matrix4 diffMatrix = prevMatrix * inverseNewMatrix; prevMatrix = newMatrix; Matrix4 reverseMatrix = ReverseMatrix(diffMatrix); if(diffMatrix.m[0] < .3f || diffMatrix.m[5] < .3f || diffMatrix.m[10] < .3f){ // too much change if(hasRadialBlur) { diffMatrix = Matrix4::Identity(); }else{ // skip blur return input; } } float movePixels = MyACos(diffMatrix.m[0]); float shutterTimeScale = .3f; movePixels = std::max(movePixels, MyACos(diffMatrix.m[5])); movePixels = std::max(movePixels, MyACos(diffMatrix.m[10])); movePixels = tanf(movePixels) / tanf(def.fovX * .5f); movePixels *= (float)dev->ScreenWidth() * .5f; movePixels *= shutterTimeScale; movePixels = std::max(movePixels, (1.f - radialBlur) * dev->ScreenWidth() * 0.5f); if(movePixels < 1.f){ // too less change, skip camera blur return input; } int levels = (int)ceilf(logf(movePixels) / logf(5.f)); if(levels <= 0) levels = 1; if(hasRadialBlur) radialBlur *= radialBlur; reverseMatrix = Matrix4::Scale(radialBlur, radialBlur, 1.f) * reverseMatrix; program->Use(); programTexture.SetValue(0); programDepthTexture.SetValue(1); programReverseMatrix.SetValue(reverseMatrix); // composite to the final image GLColorBuffer buf = input; qr.SetCoordAttributeIndex(programPosition()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, renderer->GetFramebufferManager()->GetDepthTexture()); dev->ActiveTexture(0); for(int i = 0; i < levels; i++){ GLProfiler measure(dev, "Apply [%d / %d]", i+1,levels); GLColorBuffer output = input.GetManager()->CreateBufferHandle(); programShutterTimeScale.SetValue(shutterTimeScale); dev->BindTexture(IGLDevice::Texture2D, buf.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); shutterTimeScale /= 5.f; buf = output; } dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return buf; }
GLColorBuffer GLDepthOfFieldFilter::Filter(GLColorBuffer input, float blurDepthRange, float vignetteBlur, float globalBlur) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); int w = dev->ScreenWidth(); int h = dev->ScreenHeight(); dev->Enable(IGLDevice::Blend, false); GLColorBuffer coc; globalBlur = std::min(globalBlur * 3.f, 1.f); { GLProfiler p(dev, "CoC Computation"); coc = GenerateCoC(blurDepthRange, vignetteBlur, globalBlur); } float maxCoc = (float)std::max(w, h) / 100.f; float cos60 = cosf(static_cast<float>(M_PI) / 3.f); float sin60 = sinf(static_cast<float>(M_PI) / 3.f); maxCoc *= .7f + vignetteBlur * 0.5f; maxCoc *= 1.f + 3.f * globalBlur; // reduce resolution to make it faster int divide = 1; int siz = std::max(w, h); GLColorBuffer lowbuf = input; while(siz >= 768) { divide <<= 1; siz >>= 1; lowbuf = UnderSample(lowbuf); } maxCoc /= (float)divide; dev->Viewport(0, 0, w / divide, h / divide); GLColorBuffer buf1, buf2; { GLProfiler p(dev, "Blur 1"); buf1 = Blur(lowbuf, coc, MakeVector2(0.f, -1.f) * maxCoc); } { GLProfiler p(dev, "Blur 2"); buf2 = Blur(lowbuf, coc, MakeVector2(-sin60, cos60) * maxCoc); lowbuf.Release(); } { GLProfiler p(dev, "Mix 1"); buf2 = AddMix(buf1, buf2); } //return buf2; { GLProfiler p(dev, "Blur 3"); buf1 = Blur(buf1, coc, MakeVector2(-sin60, cos60) * maxCoc); } { GLProfiler p(dev, "Blur 4"); buf2 = Blur(buf2, coc, MakeVector2(sin60, cos60) * maxCoc); } dev->Viewport(0, 0, w, h); { GLProfiler p(dev, "Mix 2"); GLColorBuffer output = FinalMix(input, buf1, buf2, coc); return output; } }