3
$\begingroup$

In my ray tracer, I render my images out to a .PPM file and then view it in photoshop. To make things easier and faster I want my ray tracer to open up another window and show the image being rendered each ray at a time like how modern renderers like Mental Ray or V-Ray do it.

How is this done? What is the most common method? I tried writing a viewer in C# that uses a picturebox to load the image which is then constantly refreshed but that doesn't work since the image cannot be shared. After asking on reddit most people suggested writing the image to an OpenGL quad as a texture but I don't want to do this as it complicates things. I've taken a look at at the setpixel function which will set the pixel's color at a specified coordinate and color, is this the way to do it?

It is really great to watch your image be rendered, it is also helpful because if your image is rendering wrong you can stop rather than waiting for the entire image to rendered and then noticing there is a problem.

(the image below is 3DS Max with Mental Ray which shows image being rendered each Ray at a time, I want to achieve this)

enter image description here

$\endgroup$
  • 2
    $\begingroup$ So you are into ray tracing and you are worried about creating an OpenGL window? :) $\endgroup$ – narthex Jan 28 '17 at 12:52
  • $\begingroup$ If you really don't want to work with anything except .ppm files, you could render to an array of initially zeroed pixel values in memory, and save a series of .ppm files at regular intervals (probably more like one image per row rather than one image per pixel, otherwise you'll have millions of image files in the folder). You'll then be one step closer to the approach described in the answer. $\endgroup$ – trichoplax Jan 28 '17 at 14:06
  • $\begingroup$ @Arjan & Trichoplax. Yes that's actually a good idea. I was thinking trying that one day but never got the time which is to write the file to disk and let some JavaScript if your browser checking every say 2s the file on disk, reload it display it in your browser)). It would work not sure about the efficiency probably poor but with canvas now it's easy (don't even need WebGL). $\endgroup$ – user18490 Jan 28 '17 at 14:30
4
$\begingroup$

This is a very common question that most people in your situation (interested or fascinated shall I say in Computer Graphics) have and a problem they want to figure out. The solution is pretty simple, though not necessarily that straightforward to implement.

I can't make a specific answer because it depends on the OS you are using, and as I said this is not something you can do in 2 lines of code.

The answer is to use some sort of library that:

  1. allows you to create a window on your system
  2. allows you to display some content (an image) in the window you created and displayed to the screen

The first task is generally quite complex regardless of the OS you use (MacOS, Windows, Linux). For the second step, you need to generally go through some sort of graphics API (like OpenGL).

So there is hope for you. One thing you can do is use some other library that works as a wrapper around 1) and 2) In other words they help you especially with the creation of the window, and then if you know OpenGL you can do the rest of the work. You will need to create some texture that you will fill with the content of your image as it gets rendered and display this texture to the screen (that's pretty basic in OpenGL though you need to know this API in order to do so).

GLFW is a great library that will allow you to do that. It's simple to use and compile and install, etc. You can alternatively use Qt but I don't recommend it unless you want to become a professional programmer.

I had some documentation about the whole process but it's offline right now. I might put it back in a few weeks but you will need to wait I am afraid.

EDIT

I am editing the answer to respond to your comment. The algorithm would look like this:

Color *buffer = Color  char [w * h];
// create a texture that you can map onto the quad stretched over the area
// of the window. You will need to create a quad rendered in the space of the
// window, aka you in 2D not 3D.
...
// now render your image using you ray-tracer
for (j = 0; j < h; ++h) {
    for (i =0; i < w; ++i) {
        buffer[j * w + i] =  trace(orig, dir, ...);
    }
    // it is not very efficient to update your window each time you have 
    // a new pixel so do this every row or every 10 rows ... you get the idea
    // copy content of your buffer into the GL texture
    // I am not using the right calls here, too lazy to find the right ones
    glCopyTexture(myGLTextureId, buffer, (sizeof(char) * 3 * w * h); 
    // do the texture binding, etc... all GL or DX stuff
    ...
    // this will update your window with the content of the buffer
    glSwapBuffer(); 
}
// now save content of buffer to image file
saveToDisk(buffer);

Windows? Arg(. You will have to use DirectX calls indeed but they 2 APIs are very close.

$\endgroup$
  • $\begingroup$ Thanks! I think I will do this with DirectX. So first I need to load the image as a texture on a quad from a specified file path (where the image is being rendered to) and then as the image is being rendered it will show up on the screen. Will I manually need to refresh the image as it is being rendered to see the progress (unload, delete, reload & repeat within DirectX) or is this unnecessary? I did this in C# with a picturebox but I got an error since I cannot read and write the file simultaneously or something like that, will the same happen here? $\endgroup$ – Arjan Singh Jan 28 '17 at 13:00
  • $\begingroup$ I'm on Windows by the way. $\endgroup$ – Arjan Singh Jan 28 '17 at 13:00
  • $\begingroup$ @ArjanSingh if I understand correctly, this answer will give you somewhere to send your partial image as you create it, rather than displaying the saved file. Treat them as two separate things. Display the image pixel by pixel as you create it in memory, and save it to file at the end when it is complete. $\endgroup$ – trichoplax Jan 28 '17 at 14:00
  • $\begingroup$ @trichoplax How can I copy the data from the image buffer to a DirectX texture? Loading, and displaying the texture isn't hard but how do I create the texture with the pixel data? Should I make this a separate question? $\endgroup$ – Arjan Singh Jan 28 '17 at 14:42
  • 1
    $\begingroup$ @ArjanSingh does sound like a separate question. $\endgroup$ – trichoplax Jan 28 '17 at 14:46
1
$\begingroup$

In QtCreator IDE (C++) any kind of image buffer - result of CPU raytracing or (what I did) frames captured from the camera can be easily rendered or painted on Widget - which is simplest part of the UI available in QtDesigner - UI designer.

You could send your ray tracing engine class to another thread and use timer which every once in a while would emit signal to send your image through signal/slot mechanism to GUI main thread and paint it on the widget. It's quite simple actually. No need of OpenGL or DirectX API.

$\endgroup$
  • $\begingroup$ If I wrote my ray tracer as a .DLL and used P/Invoke in C# to use it, could I then use the image buffer to send the image buffer to the picturebox? This is quite similar to what you said which got me thinking if I could do this with C#. $\endgroup$ – Arjan Singh Jan 28 '17 at 14:50
  • $\begingroup$ Yeah probably. I'm not into c# but Visual Studio with c# libs is pretty robust IDE too. $\endgroup$ – narthex Jan 28 '17 at 14:52
  • $\begingroup$ @narthex: it's a solution but saying that dealing with Qt is easy is not so true if you are a beginner in programming. Yes QtCreator simplified things a lot but you already introduced to the OP a lot of complex concepts (like signal/slots), etc which will take time to digest. The OP is interested in learning graphic, and so learning a graphics API is more a priority than learning Qt;-))) He can do this later ... + plus keep in mind that Qt UI are drawn in OpenGL and DX))) $\endgroup$ – user18490 Jan 28 '17 at 15:02
  • $\begingroup$ After looking online, I'm gonna write my ray tracer as a .DLL then use the data from the image buffer use PictureBox.SetPixel(x, y, color) I wanted to give my Ray Tracer a UI so writing the ray tracer in .DLL was inevitable. The OpenGL/DirectX method seems quite interesting and if the SetPixel method is too slow I'll just go with that. $\endgroup$ – Arjan Singh Jan 28 '17 at 15:11
  • $\begingroup$ @user18490 OP stated that he is looking for simple solution to view his image in UI application and this is in my opinion the simplest and involves the least lines of code instead of tedious graphical API. Also making UI application as OP posted in image not only in Qt invevitably involves learning such concepts as GUI thread and some kind of signals or events. $\endgroup$ – narthex Jan 28 '17 at 15:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.