LCOV - code coverage report
Current view: top level - engine/render - ao.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 0 173 0.0 %
Date: 2024-11-22 05:07:59 Functions: 0 19 0.0 %

          Line data    Source code
       1             : /* ao.cpp: screenspace ambient occlusion
       2             :  *
       3             :  * Screenspace ambient occlusion is a way to simulate darkening of corners which
       4             :  * do not recieve as much diffuse light as other areas. SSAO relies on the depth
       5             :  * buffer of the scene to determine areas which appear to be creases and
       6             :  * darkens those areas. Various settings allow for more or less artifact-free
       7             :  * rendition of this darkening effect.
       8             :  */
       9             : #include "../libprimis-headers/cube.h"
      10             : #include "../../shared/geomexts.h"
      11             : #include "../../shared/glemu.h"
      12             : #include "../../shared/glexts.h"
      13             : 
      14             : #include "ao.h"
      15             : #include "rendergl.h"
      16             : #include "renderlights.h"
      17             : #include "rendertimers.h"
      18             : #include "renderwindow.h"
      19             : #include "shader.h"
      20             : #include "shaderparam.h"
      21             : #include "texture.h"
      22             : 
      23             : #include "interface/control.h"
      24             : 
      25             : int aow  = -1,
      26             :     aoh  = -1;
      27             : GLuint aofbo[4] = { 0, 0, 0, 0 },
      28             :        aotex[4] = { 0, 0, 0, 0 },
      29             :        aonoisetex = 0;
      30             : 
      31           0 : VARFP(ao, 0, 1, 1, { cleanupao(); cleardeferredlightshaders(); }); //toggles ao use in general
      32             : FVARR(aoradius, 0, 5, 256);
      33             : FVAR(aocutoff, 0, 2.0f, 1e3f);
      34             : FVARR(aodark, 1e-3f, 11.0f, 1e3f);
      35             : FVARR(aosharp, 1e-3f, 1, 1e3f);
      36             : FVAR(aoprefilterdepth, 0, 1, 1e3f);
      37             : FVARR(aomin, 0, 0.25f, 1);
      38           0 : VARFR(aosun, 0, 1, 1, cleardeferredlightshaders()); //toggles ambient occlusion for sunlight
      39             : FVARR(aosunmin, 0, 0.5f, 1);
      40             : VARP(aoblur, 0, 4, 7);
      41             : VARP(aoiter, 0, 0, 4); //number of times to run ao shader (higher is smoother)
      42           0 : VARFP(aoreduce, 0, 1, 2, cleanupao());
      43           0 : VARF(aoreducedepth, 0, 1, 2, cleanupao());
      44           0 : VARFP(aofloatdepth, 0, 1, 2, initwarning("AO setup", Init_Load, Change_Shaders));
      45           0 : VARFP(aoprec, 0, 1, 1, cleanupao()); //toggles between r8 and rgba8 buffer format
      46             : VAR(aodepthformat, 1, 0, 0);
      47           0 : VARF(aonoise, 0, 5, 8, cleanupao()); //power or two scale factor for ao noise effect
      48           0 : VARFP(aobilateral, 0, 3, 10, cleanupao());
      49             : FVARP(aobilateraldepth, 0, 4, 1e3f);
      50           0 : VARFP(aobilateralupscale, 0, 0, 1, cleanupao());
      51           0 : VARF(aopackdepth, 0, 1, 1, cleanupao());
      52           0 : VARFP(aotaps, 1, 12, 12, cleanupao());
      53             : VAR(debugao, 0, 0, 4);
      54             : 
      55             : static Shader *ambientobscuranceshader = nullptr;
      56             : 
      57             : /* loadambientobscuranceshader
      58             :  *
      59             :  * creates a new ambient obscurance (ambient occlusion) object with values based
      60             :  * on current settings
      61             :  */
      62           0 : Shader *loadambientobscuranceshader()
      63             : {
      64             :     string opts;
      65           0 :     int optslen = 0;
      66             : 
      67           0 :     bool linear = aoreducedepth && (aoreduce || aoreducedepth > 1);
      68           0 :     if(linear)
      69             :     {
      70           0 :         opts[optslen++] = 'l';
      71             :     }
      72           0 :     if(aobilateral && aopackdepth)
      73             :     {
      74           0 :         opts[optslen++] = 'p';
      75             :     }
      76           0 :     opts[optslen] = '\0';
      77             : 
      78           0 :     DEF_FORMAT_STRING(name, "ambientobscurance%s%d", opts, aotaps);
      79           0 :     return generateshader(name, "ambientobscuranceshader \"%s\" %d", opts, aotaps);
      80             : }
      81             : 
      82             : //sets the ambientobscuranceshader gvar to the value created by above fxn
      83           0 : void loadaoshaders()
      84             : {
      85           0 :     ambientobscuranceshader = loadambientobscuranceshader();
      86           0 : }
      87             : 
      88             : //un-sets the ambientobscuranceshader gvar defined by loadaoshaders
      89           0 : void clearaoshaders()
      90             : {
      91           0 :     ambientobscuranceshader = nullptr;
      92           0 : }
      93             : 
      94           0 : void setupao(int w, int h)
      95             : {
      96           0 :     int sw = w>>aoreduce,
      97           0 :         sh = h>>aoreduce;
      98             : 
      99           0 :     if(sw == aow && sh == aoh)
     100             :     {
     101           0 :         return;
     102             :     }
     103           0 :     aow = sw;
     104           0 :     aoh = sh;
     105           0 :     if(!aonoisetex)
     106             :     {
     107           0 :         glGenTextures(1, &aonoisetex);
     108             :     }
     109           0 :     bvec *noise = new bvec[(1<<aonoise)*(1<<aonoise)];
     110           0 :     for(int k = 0; k < (1<<aonoise)*(1<<aonoise); ++k)
     111             :     {
     112           0 :         noise[k] = bvec(vec(randomfloat(2)-1, randomfloat(2)-1, 0).normalize());
     113             :     }
     114           0 :     createtexture(aonoisetex, 1<<aonoise, 1<<aonoise, noise, 0, 0, GL_RGB, GL_TEXTURE_2D);
     115           0 :     delete[] noise;
     116             : 
     117           0 :     bool upscale = aoreduce && aobilateral && aobilateralupscale;
     118           0 :     GLenum format = aoprec ? GL_R8 : GL_RGBA8,
     119           0 :            packformat = aobilateral && aopackdepth ? (aodepthformat ? GL_RG16F : GL_RGBA8) : format;
     120           0 :     int packfilter = upscale && aopackdepth && !aodepthformat ? 0 : 1;
     121           0 :     for(int i = 0; i < (upscale ? 3 : 2); ++i)
     122             :     {
     123             :         //create framebuffer
     124           0 :         if(!aotex[i])
     125             :         {
     126           0 :             glGenTextures(1, &aotex[i]);
     127             :         }
     128           0 :         if(!aofbo[i])
     129             :         {
     130           0 :             glGenFramebuffers(1, &aofbo[i]);
     131             :         }
     132           0 :         createtexture(aotex[i], upscale && i ? w : aow, upscale && i >= 2 ? h : aoh, nullptr, 3, i < 2 ? packfilter : 1, i < 2 ? packformat : format, GL_TEXTURE_RECTANGLE);
     133           0 :         glBindFramebuffer(GL_FRAMEBUFFER, aofbo[i]);
     134           0 :         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, aotex[i], 0);
     135             :         //make sure we have a framebuffer
     136           0 :         if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
     137             :         {
     138           0 :             fatal("failed allocating AO buffer!");
     139             :         }
     140           0 :         if(!upscale && packformat == GL_RG16F)
     141             :         {
     142           0 :             glClearColor(0, 0, 0, 0);
     143           0 :             glClear(GL_COLOR_BUFFER_BIT);
     144             :         }
     145             :     }
     146           0 :     if(aoreducedepth && (aoreduce || aoreducedepth > 1))
     147             :     {
     148             :         //create framebuffer
     149           0 :         if(!aotex[3])
     150             :         {
     151           0 :             glGenTextures(1, &aotex[3]);
     152             :         }
     153           0 :         if(!aofbo[3])
     154             :         {
     155           0 :             glGenFramebuffers(1, &aofbo[3]);
     156             :         }
     157           0 :         createtexture(aotex[3], aow, aoh, nullptr, 3, 0, aodepthformat > 1 ? GL_R32F : (aodepthformat ? GL_R16F : GL_RGBA8), GL_TEXTURE_RECTANGLE);
     158           0 :         glBindFramebuffer(GL_FRAMEBUFFER, aofbo[3]);
     159           0 :         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, aotex[3], 0);
     160             :         //make sure we have a framebuffer
     161           0 :         if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
     162             :         {
     163           0 :             fatal("failed allocating AO buffer!");
     164             :         }
     165             :     }
     166             : 
     167           0 :     glBindFramebuffer(GL_FRAMEBUFFER, 0);
     168             : 
     169           0 :     loadaoshaders();
     170           0 :     loadbilateralshaders();
     171             : }
     172             : 
     173             : /* cleanupao
     174             :  *
     175             :  * deletes the framebuffer textures for ambient obscurance (ambient occlusion)
     176             :  *
     177             :  * aofbo[0-3] and aotex[0-3] as well as aonoisetex if enabled
     178             :  * sets ao buffer width and height to -1 to indicate buffers not there
     179             :  * cleans up ao shaders
     180             :  */
     181           0 : void cleanupao()
     182             : {
     183           0 :     for(int i = 0; i < 4; ++i)
     184             :     {
     185           0 :         if(aofbo[i])
     186             :         {
     187           0 :             glDeleteFramebuffers(1, &aofbo[i]);
     188           0 :             aofbo[i] = 0;
     189             :         }
     190             :     }
     191           0 :     for(int i = 0; i < 4; ++i)
     192             :     {
     193           0 :         if(aotex[i])
     194             :         {
     195           0 :             glDeleteTextures(1, &aotex[i]);
     196           0 :             aotex[i] = 0;
     197             :         }
     198             :     }
     199           0 :     if(aonoisetex)
     200             :     {
     201           0 :         glDeleteTextures(1, &aonoisetex);
     202           0 :         aonoisetex = 0;
     203             :     }
     204           0 :     aow = aoh = -1;
     205             : 
     206           0 :     clearaoshaders();
     207           0 :     clearbilateralshaders();
     208           0 : }
     209             : 
     210             : /* initao
     211             :  *
     212             :  * sets the ao buffer depth format flag depending on the aofloatdepth variable
     213             :  */
     214           0 : void initao()
     215             : {
     216           0 :     aodepthformat = aofloatdepth ? aofloatdepth : 0;
     217           0 : }
     218             : 
     219             : /* viewao
     220             :  *
     221             :  * displays the raw output of the ao buffer, useful for debugging
     222             :  *
     223             :  * either fullscreen (if debugfullscreen is 1) or corner of screen
     224             :  */
     225           0 : void viewao()
     226             : {
     227           0 :     if(!ao || !debugao)
     228             :     {
     229           0 :         return;
     230             :     }
     231           0 :     int w = debugfullscreen ? hudw() : std::min(hudw(), hudh())/2, //if debugfullscreen, set to hudw/hudh size; if not, do small size
     232           0 :         h = debugfullscreen ? hudh() : (w*hudh())/hudw();
     233           0 :     SETSHADER(hudrect);
     234           0 :     gle::colorf(1, 1, 1);
     235           0 :     glBindTexture(GL_TEXTURE_RECTANGLE, aotex[debugao - 1]);
     236           0 :     int tw = aotex[2] ? gw : aow,
     237           0 :         th = aotex[2] ? gh : aoh;
     238           0 :     debugquad(0, 0, w, h, 0, 0, tw, th);
     239             : }
     240             : 
     241           0 : void GBuffer::renderao() const
     242             : {
     243           0 :     if(!ao)
     244             :     {
     245           0 :         return;
     246             :     }
     247           0 :     timer *aotimer = begintimer("ambient obscurance");
     248             : 
     249           0 :     if(msaasamples)
     250             :     {
     251           0 :         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
     252             :     }
     253             :     else
     254             :     {
     255           0 :         glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
     256             :     }
     257           0 :     bool linear = aoreducedepth && (aoreduce || aoreducedepth > 1);
     258           0 :     float xscale = eyematrix.a.x,
     259           0 :           yscale = eyematrix.b.y;
     260           0 :     if(linear)
     261             :     {
     262           0 :         glBindFramebuffer(GL_FRAMEBUFFER, aofbo[3]);
     263           0 :         glViewport(0, 0, aow, aoh);
     264           0 :         SETSHADER(linearizedepth);
     265           0 :         screenquad(vieww, viewh);
     266             : 
     267           0 :         xscale *= static_cast<float>(vieww)/aow;
     268           0 :         yscale *= static_cast<float>(viewh)/aoh;
     269             : 
     270           0 :         glBindTexture(GL_TEXTURE_RECTANGLE, aotex[3]);
     271             :     }
     272             : 
     273           0 :     ambientobscuranceshader->set();
     274             : 
     275           0 :     glBindFramebuffer(GL_FRAMEBUFFER, aofbo[0]);
     276           0 :     glViewport(0, 0, aow, aoh);
     277           0 :     glActiveTexture(GL_TEXTURE1);
     278             : 
     279           0 :     if(msaasamples)
     280             :     {
     281           0 :         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
     282             :     }
     283             :     else
     284             :     {
     285           0 :         glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
     286             :     }
     287             : 
     288           0 :     LOCALPARAM(normalmatrix, matrix3(cammatrix));
     289           0 :     glActiveTexture(GL_TEXTURE2);
     290           0 :     glBindTexture(GL_TEXTURE_2D, aonoisetex);
     291           0 :     glActiveTexture(GL_TEXTURE0);
     292             : 
     293           0 :     LOCALPARAMF(tapparams, aoradius*eyematrix.d.z/xscale, aoradius*eyematrix.d.z/yscale, aoradius*aoradius*aocutoff*aocutoff);
     294           0 :     LOCALPARAMF(contrastparams, (2.0f*aodark)/aotaps, aosharp);
     295           0 :     LOCALPARAMF(offsetscale, xscale/eyematrix.d.z, yscale/eyematrix.d.z, eyematrix.d.x/eyematrix.d.z, eyematrix.d.y/eyematrix.d.z);
     296           0 :     LOCALPARAMF(prefilterdepth, aoprefilterdepth);
     297           0 :     screenquad(vieww, viewh, aow/static_cast<float>(1<<aonoise), aoh/static_cast<float>(1<<aonoise));
     298             : 
     299           0 :     if(aobilateral)
     300             :     {
     301           0 :         if(aoreduce && aobilateralupscale)
     302             :         {
     303           0 :             for(int i = 0; i < 2; ++i)
     304             :             {
     305           0 :                 setbilateralshader(aobilateral, i, aobilateraldepth);
     306           0 :                 glBindFramebuffer(GL_FRAMEBUFFER, aofbo[i+1]);
     307           0 :                 glViewport(0, 0, vieww, i ? viewh : aoh);
     308           0 :                 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[i]);
     309           0 :                 glActiveTexture(GL_TEXTURE1);
     310           0 :                 if(msaasamples)
     311             :                 {
     312           0 :                     glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
     313             :                 }
     314             :                 else
     315             :                 {
     316           0 :                     glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
     317             :                 }
     318           0 :                 glActiveTexture(GL_TEXTURE0);
     319           0 :                 screenquad(vieww, viewh, i ? vieww : aow, aoh);
     320             :             }
     321           0 :         }
     322             :         else
     323             :         {
     324           0 :             for(int i = 0; i < 2 + 2*aoiter; ++i)
     325             :             {
     326           0 :                 setbilateralshader(aobilateral, i%2, aobilateraldepth);
     327           0 :                 glBindFramebuffer(GL_FRAMEBUFFER, aofbo[(i+1)%2]);
     328           0 :                 glViewport(0, 0, aow, aoh);
     329           0 :                 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[i%2]);
     330           0 :                 glActiveTexture(GL_TEXTURE1);
     331           0 :                 if(linear)
     332             :                 {
     333           0 :                     glBindTexture(GL_TEXTURE_RECTANGLE, aotex[3]);
     334             :                 }
     335           0 :                 else if(msaasamples)
     336             :                 {
     337           0 :                     glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
     338             :                 }
     339             :                 else
     340             :                 {
     341           0 :                     glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
     342             :                 }
     343           0 :                 glActiveTexture(GL_TEXTURE0);
     344           0 :                 screenquad(vieww, viewh);
     345             :             }
     346             :         }
     347             :     }
     348           0 :     else if(aoblur)
     349             :     {
     350             :         std::array<float, maxblurradius+1> blurweights,
     351             :                                            bluroffsets;
     352           0 :         setupblurkernel(aoblur, blurweights.data(), bluroffsets.data());
     353           0 :         for(int i = 0; i < 2+2*aoiter; ++i)
     354             :         {
     355           0 :             glBindFramebuffer(GL_FRAMEBUFFER, aofbo[(i+1)%2]);
     356           0 :             glViewport(0, 0, aow, aoh);
     357           0 :             setblurshader(i%2, 1, aoblur, blurweights.data(), bluroffsets.data(), GL_TEXTURE_RECTANGLE);
     358           0 :             glBindTexture(GL_TEXTURE_RECTANGLE, aotex[i%2]);
     359           0 :             screenquad(aow, aoh);
     360             :         }
     361             :     }
     362             : 
     363           0 :     glBindFramebuffer(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
     364           0 :     glViewport(0, 0, vieww, viewh);
     365             : 
     366           0 :     endtimer(aotimer);
     367             : }

Generated by: LCOV version 1.14