RenderKit / ospray

An Open, Scalable, Portable, Ray Tracing Based Rendering Engine for High-Fidelity Visualization
http://ospray.org
Apache License 2.0
997 stars 182 forks source link

Enabling accumulation buffer causes altered background color #393

Closed paulmelis closed 4 years ago

paulmelis commented 4 years ago
#include <ospray/ospray_cpp.h>

using namespace ospcommon::math;
using namespace ospray::cpp;

const int W = 1024;
const int H = 1024;

void writePPM(const char *fileName, const vec2i &size, const uint32_t *pixel)
{
  FILE *file = fopen(fileName, "wb");
  if (file == nullptr) {
    fprintf(stderr, "fopen('%s', 'wb') failed: %d", fileName, errno);
    return;
  }
  fprintf(file, "P6\n%i %i\n255\n", size.x, size.y);
  unsigned char *out = (unsigned char *)alloca(3 * size.x);
  for (int y = 0; y < size.y; y++) {
    const unsigned char *in =
        (const unsigned char *)&pixel[(size.y - 1 - y) * size.x];
    for (int x = 0; x < size.x; x++) {
      out[3 * x + 0] = in[4 * x + 0];
      out[3 * x + 1] = in[4 * x + 1];
      out[3 * x + 2] = in[4 * x + 2];
    }
    fwrite(out, 3 * size.x, sizeof(char), file);
  }
  fprintf(file, "\n");
  fclose(file);
}

int main(int argc, const char *argv[])
{
    ospInit(&argc, argv);

    World world;
    world.commit();

    Renderer renderer("scivis");
    renderer.setParam("bgColor", vec3f(1.0f, 1.0f, 1.0f));
    renderer.commit();

    Camera camera("perspective");
    camera.setParam("aspect", 1.0f*W/H);
    camera.commit();

    FrameBuffer fb(vec2i(W,H), OSP_FB_SRGBA, OSP_FB_COLOR);
    fb.clear();

    fb.renderFrame(renderer, camera, world).wait();

    uint32_t *pixels = (uint32_t *)fb.map(OSP_FB_COLOR);
    writePPM("coloronly.ppm", vec2i(W,H), pixels);
    fb.unmap(pixels);    

    fb = FrameBuffer(vec2i(W,H), OSP_FB_SRGBA, OSP_FB_COLOR|OSP_FB_ACCUM);    

    fb.renderFrame(renderer, camera, world).wait();

    pixels = (uint32_t *)fb.map(OSP_FB_COLOR);
    writePPM("colorandaccum.ppm", vec2i(W,H), pixels);
    fb.unmap(pixels);    

}
paulm@cmstorm 09:02:~/concepts/ospray-python/utests$ hexdump -C coloronly.ppm | head
00000000  50 36 0a 31 30 32 34 20  31 30 32 34 0a 32 35 35  |P6.1024 1024.255|
00000010  0a ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00300010  ff 0a                                             |..|
00300012
paulm@cmstorm 09:03:~/concepts/ospray-python/utests$ hexdump -C colorandaccum.ppm | head
00000000  50 36 0a 31 30 32 34 20  31 30 32 34 0a 32 35 35  |P6.1024 1024.255|
00000010  0a fe fe fe fe fe fe fe  fe fe fe fe fe fe fe fe  |................|
00000020  fe fe fe fe fe fe fe fe  fe fe fe fe fe fe fe fe  |................|
*
00300010  fe 0a                                             |..|
00300012

Looks like you can't get pure white as background whenever the accumulation buffer is enabled.

johguenther commented 4 years ago

OK, this is actually an artifact of floating-point precision (in combination that we round down when converting colors from float to byte): using an float framebuffer we see that the result is 0x3f7fffff for the first case and 0x3f7ffffe for the 2nd (accumulating) case. Those numbers are almost 1.0 (one and 2 ulps less, respectively). Converting both floats to byte the result is 0xfe (254), because we round down. When additionally applying the sRGB transformation before conversion, the first float rounds exactly to 1.0 (thus the byte will be 255), the 2nd stays one ulp below 1.0...

So, we could (properly) round when converting to bytes, which would solve this issue.