2
$\begingroup$

(I am new to Computer Graphics in general)

I am learning how to ray trace from a book called ''Peter Shirley - Ray Tracing in One Weekend''. In the book, the code is written in C++. I have intermediate-advanced level understanding of good ol' C, but I've never written even simple programs in C++. I don't pretend to understand everything the code says in the book. But, that is the fun part -- figuring it out.

But, for ray tracing, even C is slow. And writing GLSL fragment shaders is fast, even on my potato PC. And GLSL is closer to C than to C++. So, I'm trying to follow through the book using GLSL. But, GLSL has many limitations and I was hoping if you could teach me how to get around those limitations.

  1. Pointers. GLSL doesn't have pointers. In the book, there is a function bool hit_sphere(const vec3& center, float radius, const ray& r) I believe that ''address of'' operator just points to the variable that is passed when the function is called. Without pointers, how to call a function by reference in GLSL?

  2. Late binding. In the book, every object is a class which exposes an interface function called hit which returns if a ray hits the object. How does one implement that in GLSL structs?

$\endgroup$
  • $\begingroup$ In 1) those a references, in glsl you'll just pass things as they are. For 2) you don't have polymorphism, so you can split your spheres, triangles, etc. in separate arrays and deal with those in separate parts of the code. Here's something you can check out: github.com/GraphicsProgramming/RVPT $\endgroup$ – lightxbulb Aug 8 at 11:43
3
$\begingroup$

I'll get to the specifics of your question presently, but first it is important to discuss the broad thesis of your idea: porting C++ code as is to GLSL.

This is a bad idea. The execution model of shaders is fundamentally different from the way a normal program (even a multi-threaded program) works. Attempting to port such code from one execution model to another is not a good idea. Your best bet is to try to make the algorithms involved fit the nature of the rendering pipeline. That is, you need to understand how rendering works, then try to apply the mechanics of rendering to the problem you're trying to solve.

For example, in regular CPU code, you might implement a ray-tracer by iterating over a bunch of locations on the screen and doing ray-scene intersection tests for each of them. Doing that iteration on the GPU in GLSL code is wrong. Instead, you should map rendering concepts to the needs of a ray-tracing algorithm. You might have each fragment shader do a single ray/scene processing step, with the fragment shader inputs being a direction from the camera. There would be no explicit loop over the screen's pixels; the loop happens implicitly in the rasterizer. The rasterizer generates a fragment shader invocation for each pixel-sized area of a rendered object. You would simply render a single quad that covers the whole screen.

Things like that are how you need to think of these kinds of problems in a GPU-centric computation model.


GLSL does not have pointers. But it does have shader storage buffer objects, which allow you to define arbitrarily large regions of memory that the shader can read from. A "pointer" in this model is just an index into an array of data structures. You have to do the indexing explicitly in GLSL code.

Similarly, any form of "late binding" can just be a switch statement based on some value in a data structure. The different casees define which function to call.

| improve this answer | |
$\endgroup$

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.