GLColorBuffer GLLensFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensTexture("mainTexture"); static GLProgramUniform lensFov("fov"); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensTexture(lens); lensFov(lens); lens->Use(); client::SceneDefinition def = renderer->GetSceneDef(); lensFov.SetValue(tanf(def.fovX * .5f), tanf(def.fovY * .5f)); lensTexture.SetValue(0); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); qr.SetCoordAttributeIndex(lensPosition()); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
GLColorBuffer GLLensDustFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); UpdateNoise(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("mainTexture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLColorBuffer downSampled = DownSample(input, r_hdr ? false : true); downSampled = GaussianBlur(downSampled, false); downSampled = GaussianBlur(downSampled, true); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); levels.reserve(10); // create downsample levels for(int i = 0; i < 10; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = downSampled; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; if(newW <= 1 || newH <= 1) break; GLColorBuffer newLevel = DownSample(prevLevel); newLevel = GaussianBlur(newLevel, false); newLevel = GaussianBlur(newLevel, true); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = alpha; GLColorBuffer curLevel = levels[i].buffer; float sx = .25f / curLevel.GetWidth(); float sy = .25f / curLevel.GetHeight(); for(int j = 0; j < 4; j++) { if(i < (int)levels.size() - 1) { curLevel = levels[i].retBuf[j]; } GLColorBuffer targLevel = levels[i - 1].buffer; GLColorBuffer targRet = input.GetManager()->CreateBufferHandle(targLevel.GetWidth(), targLevel.GetHeight(), false); levels[i - 1].retBuf[j] = targRet; dev->BindFramebuffer(IGLDevice::Framebuffer, targRet.GetFramebuffer()); dev->Viewport(0, 0, targRet.GetWidth(), targRet.GetHeight()); dev->BindTexture(IGLDevice::Texture2D, targLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); dev->Enable(IGLDevice::Blend, false); qr.Draw(); float cx = 0.f, cy = 0.f; switch(j){ case 0: cx = sx; break; case 1: cx = -sx; break; case 2: cy = sy; break; case 3: cy = -sy; break; } dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); thruTexCoordRange.SetValue(cx, cy, 1.f, 1.f); dev->Enable(IGLDevice::Blend, true); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } } static GLProgramAttribute dustPosition("positionAttribute"); static GLProgramUniform dustDustTexture("dustTexture"); static GLProgramUniform dustBlurTexture1("blurTexture1"); static GLProgramUniform dustBlurTexture2("blurTexture2"); static GLProgramUniform dustBlurTexture3("blurTexture3"); static GLProgramUniform dustBlurTexture4("blurTexture4"); static GLProgramUniform dustInputTexture("inputTexture"); static GLProgramUniform dustNoiseTexture("noiseTexture"); static GLProgramUniform dustNoiseTexCoordFactor("noiseTexCoordFactor"); dustPosition(dust); dustDustTexture(dust); dustBlurTexture1(dust); dustBlurTexture2(dust); dustBlurTexture3(dust); dustBlurTexture4(dust); dustInputTexture(dust); dustNoiseTexture(dust); dustNoiseTexCoordFactor(dust); dust->Use(); float facX = renderer->ScreenWidth() / 128.f; float facY = renderer->ScreenHeight() / 128.f; dustNoiseTexCoordFactor.SetValue(facX, facY, facX / 128.f, facY / 128.f); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel1 = levels[0].retBuf[0]; GLColorBuffer topLevel2 = levels[0].retBuf[1]; GLColorBuffer topLevel3 = levels[0].retBuf[2]; GLColorBuffer topLevel4 = levels[0].retBuf[3]; qr.SetCoordAttributeIndex(dustPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel1.GetTexture()); dev->ActiveTexture(2); dev->BindTexture(IGLDevice::Texture2D, topLevel2.GetTexture()); dev->ActiveTexture(3); dev->BindTexture(IGLDevice::Texture2D, topLevel3.GetTexture()); dev->ActiveTexture(4); dev->BindTexture(IGLDevice::Texture2D, topLevel4.GetTexture()); dev->ActiveTexture(5); dustImg->Bind(IGLDevice::Texture2D); dev->ActiveTexture(6); dev->BindTexture(IGLDevice::Texture2D, noiseTex); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); dustBlurTexture1.SetValue(2); dustBlurTexture2.SetValue(1); dustBlurTexture3.SetValue(3); dustBlurTexture4.SetValue(4); dustDustTexture.SetValue(5); dustNoiseTexture.SetValue(6); dustInputTexture.SetValue(0); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
GLColorBuffer GLBloomFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("texture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLProgram *gammaMix = renderer->RegisterProgram("Shaders/PostFilters/GammaMix.program"); static GLProgramAttribute gammaMixPosition("positionAttribute"); static GLProgramUniform gammaMixTexture1("texture1"); static GLProgramUniform gammaMixTexture2("texture2"); static GLProgramUniform gammaMixMix1("mix1"); static GLProgramUniform gammaMixMix2("mix2"); gammaMixPosition(gammaMix); gammaMixTexture1(gammaMix); gammaMixTexture2(gammaMix); gammaMixMix1(gammaMix); gammaMixMix2(gammaMix); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); // create downsample levels for(int i = 0; i < 6; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = input; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; GLColorBuffer newLevel = input.GetManager()->CreateBufferHandle(newW, newH); thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); dev->BindTexture(IGLDevice::Texture2D, prevLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, newLevel.GetFramebuffer()); dev->Viewport(0, 0, newLevel.GetWidth(), newLevel.GetHeight()); thruTexCoordRange.SetValue(0.f, 0.f, (float)newLevel.GetWidth() * 2.f / (float)prevW, (float)newLevel.GetHeight() * 2.f / (float)prevH); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = sqrtf(alpha); GLColorBuffer curLevel = levels[i].buffer; GLColorBuffer targLevel = levels[i - 1].buffer; thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, targLevel.GetFramebuffer()); dev->Viewport(0, 0, targLevel.GetWidth(), targLevel.GetHeight()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel = levels[0].buffer; gammaMix->Use(); qr.SetCoordAttributeIndex(gammaMixPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); gammaMixTexture1.SetValue(0); gammaMixTexture2.SetValue(1); gammaMixMix1.SetValue(.8f, .8f, .8f); gammaMixMix2.SetValue(.2f, .2f, .2f); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
GLColorBuffer GLColorCorrectionFilter::Filter(GLColorBuffer input, Vector3 tintVal) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensTexture("mainTexture"); static GLProgramUniform saturation("saturation"); static GLProgramUniform enhancement("enhancement"); static GLProgramUniform tint("tint"); saturation(lens); enhancement(lens); tint(lens); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensTexture(lens); lens->Use(); tint.SetValue(tintVal.x, tintVal.y, tintVal.z); const client::SceneDefinition &def = renderer->GetSceneDef(); if (settings.r_hdr) { // when HDR is enabled ACES tone mapping is applied first, so // lower enhancement value is required if (settings.r_bloom) { saturation.SetValue(0.8f * def.saturation * settings.r_saturation); enhancement.SetValue(0.1f); } else { saturation.SetValue(0.9f * def.saturation * settings.r_saturation); enhancement.SetValue(0.0f); } } else { if (settings.r_bloom) { // make image sharper saturation.SetValue(.85f * def.saturation * settings.r_saturation); enhancement.SetValue(0.7f); } else { saturation.SetValue(1.f * def.saturation * settings.r_saturation); enhancement.SetValue(0.3f); } } lensTexture.SetValue(0); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); qr.SetCoordAttributeIndex(lensPosition()); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
GLColorBuffer GLFogFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); GLProgram *lens = renderer->RegisterProgram("Shaders/PostFilters/Fog.program"); static GLProgramAttribute lensPosition("positionAttribute"); static GLProgramUniform lensShadowMapTexture("shadowMapTexture"); static GLProgramUniform lensCoarseShadowMapTexture("coarseShadowMapTexture"); static GLProgramUniform lensColorTexture("colorTexture"); static GLProgramUniform lensDepthTexture("depthTexture"); static GLProgramUniform lensFov("fov"); static GLProgramUniform lensViewOrigin("viewOrigin"); static GLProgramUniform lensViewAxisUp("viewAxisUp"); static GLProgramUniform lensViewAxisSide("viewAxisSide"); static GLProgramUniform lensViewAxisFront("viewAxisFront"); static GLProgramUniform zNearFar("zNearFar");; static GLProgramUniform fogColor("fogColor"); static GLProgramUniform fogDistance("fogDistance"); dev->Enable(IGLDevice::Blend, false); lensPosition(lens); lensShadowMapTexture(lens); lensCoarseShadowMapTexture(lens); lensColorTexture(lens); lensDepthTexture(lens); lensFov(lens); lensViewOrigin(lens); lensViewAxisUp(lens); lensViewAxisSide(lens); lensViewAxisFront(lens); zNearFar(lens); fogColor(lens); fogDistance(lens); lens->Use(); client::SceneDefinition def = renderer->GetSceneDef(); lensFov.SetValue(tanf(def.fovX * .5f), tanf(def.fovY * .5f)); lensViewOrigin.SetValue(def.viewOrigin.x, def.viewOrigin.y, def.viewOrigin.z); lensViewAxisUp.SetValue(def.viewAxis[1].x, def.viewAxis[1].y, def.viewAxis[1].z); lensViewAxisSide.SetValue(def.viewAxis[0].x, def.viewAxis[0].y, def.viewAxis[0].z); lensViewAxisFront.SetValue(def.viewAxis[2].x, def.viewAxis[2].y, def.viewAxis[2].z); zNearFar.SetValue(def.zNear, def.zFar); Vector3 fogCol = renderer->GetFogColor(); fogCol *= fogCol; // linearize fogColor.SetValue(fogCol.x, fogCol.y, fogCol.z); fogDistance.SetValue(128.f); lensColorTexture.SetValue(0); lensDepthTexture.SetValue(1); lensShadowMapTexture.SetValue(2); lensCoarseShadowMapTexture.SetValue(3); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); dev->Enable(IGLDevice::Blend, false); qr.SetCoordAttributeIndex(lensPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, input.GetManager()->GetDepthTexture()); dev->ActiveTexture(2); dev->BindTexture(IGLDevice::Texture2D, renderer->GetMapShadowRenderer()->GetTexture()); dev->ActiveTexture(3); dev->BindTexture(IGLDevice::Texture2D, renderer->GetMapShadowRenderer()->GetCoarseTexture()); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); qr.Draw(); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, 0); return output; }
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; }