Skip to main content
Up and Coming
April 26, 2013

Partially/fully pre-rendered ray tracing...

I'm sure you're all aware of the image quality that can be had from ray tracing. While pulling it off with impressive results in real-time is becoming more of a reality, it's still some ways away, and even then it's not quite on par with the quality we see in big budget movies today. But what if we could view pre-rendered scenes with limited 6DOF and in 3D? Well, that's the whole purpose of this post! :D

I have been interested in the concept of pre-rendered still and animated stereoscopic "panoramas" for the past several months now, and have been thinking about how it could be accomplished. Well, I figured I would share what has been on my mind. It's my understanding there are no implementations of panorama viewers that allow for both, 6DOF and stereoscopic viewing. As far as I know, the method I'm going to describe has not been done before, and while I unfortunately don't have the skills to implement an example myself, I hope someone might find these thoughts interesting and useful enough to give it a shot. :)

Off the top of my head, some of the applications where this could be useful is something as simple as sitting on an extremely detailed beach, to interactive media with limited or no real-time dynamic visuals such as certain types of adventure games, to being a "fly on the wall" in a Pixar movie. The primary benefit of this is the quality of visuals that can be achieved without having to do it in real-time. Well, at least not having to render the entire scene in real-time.

The most appropriate and descriptive name for the method that I can think of is 'light-field cube ray mapping'. Maybe that sounds like nonsense but bear with me for a moment. Lets say you wish to view a scene from the vantage point of a person sitting on a stool in the middle of a CG room. Now imagine enclosing that person's head in a virtual glass box that's big enough to allow for comfortable but limited head movement in all directions (rotation and position). This virtual box will form the basis of both the light-field cube camera during the pre-rendering of the scene, as well the area we will need to perform ray lookups during run-time.


There's no specific way pre-rendering the scene and capturing the data to the light-field cube needs to be performed, but I'll describe the way I had in mind. Each face of the cube contains a finite array of elements somewhat similar to pixels, but instead of recording just a single color value, it captures the angular data of the light rays entering it as well as their color information. Each element must likely be able to "capture" more than one ray (though in practice sometimes it may capture none). What you end up with is 6 faces of the cube (you don't necessarily have to do all 6 faces) with all the various light rays that entered it during pre-rendering mapped along the array of surface elements (ray maps). I just want to point out that one consequence of this approach is that the ray tracing engine for the pre-render phase would need to start from the light source, rather than the common method of starting from the camera and following it to the source in reverse. As you can probably imagine, capturing video would essentially create constantly changing ray maps.


In order to view the scene at run-time, we start with a typical ray tracer, where a ray extends outwards from the camera viewport, but it only intersects a single object - an element on the inside surface of the cube - and performs a lookup for a ray of the matching angle. The performance of this method will heavily depend on the efficiency of the lookup algorithm, but an optimized system should be substantially faster than a typical ray tracer for a given detail level. Of course, the drawback is that dynamically drawn elements are pretty much impossible unless you also incorporate aspects of traditional 3D engine which you could use for the purpose of rendering certain elements in real time.

You can take this concept a step further and fill an entire scene (or at least the areas the viewport can be) with the light-field cube cameras, and traverse from one light-field cube to the next in real time. This would also make rendering dynamic elements more feasible.

For content that wouldn't be affected by these limitations, the visual quality it could produce at a given performance level might be hard to achieve any other way.

    25 replies

    Up and Coming
    April 27, 2013
    "mdk" wrote:
    Maybe a bit offtopic, but are you familiar with the Brigade game engine? Brigade does real-time pathtracing.
    It's pretty impressive what it can do, but it's still quite not there yet. I've been thinking that in VR a pathtracing solutions might work a bit better if we had eye tracking. That way it's possible to pump more samples to the areas that the player is actually looking at. Brigade also is an unbiased meaning that it doesn't fake things that much. I would rather have something that was 90% as good, but was biased and way faster. Maybe in a few years when Nvidia launches it's Volta series cards we might have enough horsepower to run things like this without noise.

    http://raytracey.blogspot.co.nz/
    http://www.youtube.com/watch?feature=player_embedded&v=VtLuStcTRXQ#!


    that looks great! similar to what I've seen here
    http://madebyevan.com/webgl-path-tracing/

    it looks like they're using a similar effect to haze the image while resolving the final render.
    maybe not ideal for the rift though since we're already suffering from visible low resolution of the display.
    Up and Coming
    April 27, 2013
    "msat" wrote:
    I'm a bit surprised that view synthesis is more efficient on a spherical surface rather than a flat one, particularly when the view is not at the center. I'll take you word for it though.


    Well, actually you can use any convex closed surface; spheres are just very convenient, and I suspect their uniformity will lead to fewer artifacts (cubes tend to suffer from issues at their corners).

    "msat" wrote:
    I imagine capturing the light-field of a volume directly during the rendering process would be the most ideal, but you're just making do with the tools available to you, correct? I'm still trying to wrap my head around the concept and inherent difficulties of using cameras to capture the light-field like this. Do you set the projection plane for each capture to be along the surface of the sphere, and take progressive snapshots at varying FoV?


    In the ideal case, you would have some surface, and at every point on the surface you would capture the incoming light from every possible direction. Then, provided the interior of this surface is empty, you can reconstruct any viewpoint in the interior by just rearranging the right (position, direction) samples from the surface.

    You're right that if you had a raytracer, then you could get a more uniform coverage on the surface compared to using cameras, since placing cameras produces a 'lumpy' spatial coverage (i.e., you have better angular than spatial coverage).

    However, the benefit is that you can easily retrofit any existing rendering pipeline (just render a bunch of views placed on the surface of a sphere). All the cameras have the same fov (ideally this would be a fully 180 degrees, but I used a more conservative 90). Here's a mockup of the arrangement, where the sphere is just there for reference (except imagine more cameras spread out over the whole sphere, and less haphazardly arranged):



    "msat" wrote:
    I'm curious about what you mean by 'depth information'. In what way is this information used for view synthesis? Are you calculating the light-field from the images in real-time, or did you compute a map ahead of time and use that for view synthesis? Also, what kind of frame rate are you achieving?


    The light-field is just stored as a bunch of regular images along with their camera locations/orientations. The depth information is stored as a low-res cube-map from the center of the sphere, where the RGB values in the map encode the scene depth (basically the z-buffer value). It's hard to explain without a diagram (I'll make one later), but if you know the scene depth, you can more intelligently choose which light-field samples to use for each pixel in the synthesized view. If you had an infinite number of cameras, then depth wouldn't help (because the image would already be perfect).

    Digression: I don't know if this explanation will make any sense, but here goes. With a finite number of cameras, when you want a sample from the surface, it is unlikely that a camera was placed at exactly that point on the surface, so you have to average nearby cameras. This is like building a synthetic lens whose size is related to how far away the cameras are that you're averaging; as the number of cameras goes to infinity, this synthetic lens becomes a point. A pinhole camera has infinite depth of field (everything is in focus), so hence, with an infinite number of cameras the image would be perfect. However, with a finite number of cameras, and thus a finite size synthetic lens, the lens has a depth of field, and this gets smaller as the lens gets bigger (less stuff is in focus). What depth information lets you do is 'focus' the synthetic lens at every pixel to get a sharper image.

    Without depth, I'm getting 60+ fps on a GTX 260 with 600 views (I could do more views but I run out of texture memory). With depth, I can do about 300 views before the framerate starts to suffer (the shaders for using depth are more complicated).
    msatAuthor
    Up and Coming
    April 27, 2013
    I think I can see how using a concave surface might be beneficial in terms of reducing errors, but I would imagine that determining a point in the surface relative to the viewport would require higher precision than if it was a flat surface.

    As for corner issues using cubes, shouldn't it be possible to eliminate them if each surface extends a little bit beyond the points where they intersect? For example say it's something like -> # but in 3D of course (and not skewed, heh).

    "Pyry" wrote:
    In the ideal case, you would have some surface, and at every point on the surface you would capture the incoming light from every possible direction. Then, provided the interior of this surface is empty, you can reconstruct any viewpoint in the interior by just rearranging the right (position, direction) samples from the surface.


    Similar to the way you resolve this at run-time, couldn't you create such a surface map of incoming rays ahead of time and use that directly? Do you see any benefits of doing it like that?

    Thanks for the explanation of the method you're using. I think I have a grip on why you need scene depth information particularly when you limit the number of images, as you need a way to determine where a pixel may have come from in a given image due to limited spacial resolution (correct?).

    Re: performance - That sounds quite good considering the age of your GPU. I figured it would chew through memory though. Out of curiosity, what is the resolution and bit-depth of each view?
    msatAuthor
    Up and Coming
    April 27, 2013
    "msat" wrote:
    Similar to the way you resolve this at run-time, couldn't you create such a surface map of incoming rays ahead of time and use that directly? Do you see any benefits of doing it like that?


    Now that I think of it, I guess the depth map-less method is essentially the same thing, it's just a different way of "encoding" the incoming rays.
    Up and Coming
    May 1, 2013
    "msat" wrote:
    I figured it would chew through memory though. Out of curiosity, what is the resolution and bit-depth of each view?


    I'm using 512x512 images; as jpgs, 600 of them is about 50 megabytes, however, uncompressed they're about a megabyte each, and my graphics card only has ~900 mb of ram (which is why if I try 1000 views my whole computer locks up).

    I just got my rift today, so I'll go ahead and get it working on the rift. If you want, I can clean up the code a bit and release a version that lets you use your own image sets, if you want to try rendering from some program of your choice.
    Up and Coming
    December 8, 2013
    "Pyry" wrote:
    "msat" wrote:
    I figured it would chew through memory though. Out of curiosity, what is the resolution and bit-depth of each view?


    I'm using 512x512 images; as jpgs, 600 of them is about 50 megabytes, however, uncompressed they're about a megabyte each, and my graphics card only has ~900 mb of ram (which is why if I try 1000 views my whole computer locks up).

    I just got my rift today, so I'll go ahead and get it working on the rift. If you want, I can clean up the code a bit and release a version that lets you use your own image sets, if you want to try rendering from some program of your choice.

    Although you lose some (significant) quality, many GPUs can use compressed DXT textures, which could let you fit more images into your VRAM. For example, here is a little tool from the "demo scene" crowd:
    http://nothings.org/stb/stb_dxt.h
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Participant
    December 20, 2013
    I have been considering using fully rendered stereo FMV with the oculus. It would work as follows: you render the scene onto a cube, use it in the same way you do with a skybox but you do this once for each eye. Then you just load up the stereo pre-rendered scene and render the skyboxes in eye with the oculus shader.

    I am working on putting a demo together to render a simple scene onto a skybox per eye and then through the oculus. I will provide a link when I have it working.

    Until then you can what stereo 360deg imagery is like rendered in the rift by checking it out in this thread: https://developer.oculusvr.com/forums/viewtopic.php?f=28&t=5285.

    An online demo of rendering a skybox per eye using photographs can be found at: http://www.aplweb.co.uk/experiments/oculus_3dvision.html
    Participant
    December 28, 2013
    I have put together a demo but unfortunately the concept of using stereo cube maps does not work as you can't render from a fixed point in 3d for each eye, as the eye position moves as the player looks around.

    The other way to do it would be to pre-render a scene onto one cube map and then render with an offset from the center for each eye - this works fine but does not preserve the stereo for each eye so it does not feel 3d.
    Up and Coming
    December 28, 2013
    "mrboggieman" wrote:
    I have put together a demo but unfortunately the concept of using stereo cube maps does not work as you can't render from a fixed point in 3d for each eye, as the eye position moves as the player looks around.

    The other way to do it would be to pre-render a scene onto one cube map and then render with an offset from the center for each eye - this works fine but does not preserve the stereo for each eye so it does not feel 3d.

    Stereoscopic cube maps work just fine if you do it right...

    I have lots of pairs of stereo cube maps that work great for me. I am warping them by bouncing off a pair of spheres instead of using the Rift warp shader, but the Rift shaders should work fine too.

    The key is to use a pair of cube maps, and use the left cube map in the fragment shader on the left half of the screen, and the right cube map for the right half of the screen. The cube map photos were taken with a pair of cameras (from lots of photo strips) and match the corresponding eye positions as the player looks around, so all is well...

    I converted various sphere map image pairs I downloaded off the interwebz, including some from this thread:
    http://www.mtbs3d.com/phpBB/viewtopic.php?f=138&t=16502&p=117806#p117806

    Here are some gigapixel stereo photo pairs, which you can convert to cubemaps:
    http://csc.lsu.edu/~kooima/panorama/

    I use 2Kx2K cubemap faces for best results. It really does work very well, and spherical reflection warping gives sharper images than the Rift warp post-processing method. You can even do it in Unity3D:
    http://paulbourke.net/dome/unity3d/
    But you need to extend this method for sterescopic viewing by using a left/right pair of cube maps (with correct "eye offset" baked in), as mentioned above.
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Participant
    December 29, 2013
    Many thanks for the reply but could you expand on baking the eye offset, technically speaking.

    If you use cameras, one for each eye, how do you keep the separating distance between the eyes consistent whilst looking around - I assume you attach them to be fixed distance and then pivot them around that point - doesn't this only really keep the separation distance for the middle pixel in the result image for the direction you are facing.

    I have thought about ray tracing this way and use sphere maps instead of cube maps but there would be too much distortion.

    There are some 360 stereo demos in this thread: viewtopic.php?f=28&t=5285 but they don't feel right when I view them in the oculus - I don't know if this is because there is a time delay for each eye and so the result imagery is different and makes you feel sick or if it is the varying separation distance as you look around.