View Full Version : Ray intersection with GLSL

02-27-2018, 01:28 PM
I'm looking for to simulate the reflection effect using ray tracing on GLSL, however I could not find good references, examples or tutorial related to this topic. When I got some interesting data, the method is limited for specific object's surfaces (e.g. sphere, box, cylinder...) and it needs to know object's position and radius; it is not my case. I also know the GLSL does not support recursive functions, but as far as I know the ray tracing can be done iteratively.

My goal is to simulate the reverberation process for an acoustic sensor as follows: primary reflections by rasterization; and secondary reflections by ray tracing. When a ray hits the object's surface, the distance and normal values are measured.

My scene with all objects is modeled using OpenSceneGraph, and I have used GLSL to handle the normal and position data from the viewpoint on GPU.

Follows below my current GLSL code. At this moment, I am able to calculate the ray parameters (world position and direction vector values, for each pixel), however I do not know how to calculate the data when a ray hits a surface.

Thanks in advance. Any help is very much welcome.

Vertex shader:

#version 130

uniform mat4 osg_ViewMatrixInverse;

out vec3 positionEyeSpace;
out vec3 normalEyeSpace;
uniform vec3 cameraPos;

// ray definition, with an origin point and a direction vector
struct Ray {
vec3 origin;
vec3 direction;

void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

// world space
mat4 modelWorld = osg_ViewMatrixInverse * gl_ModelViewMatrix;
vec3 positionWorldSpace = vec3(modelWorld * gl_Vertex);
vec3 normalWorldSpace = mat3(modelWorld) * gl_Normal;

// eye space
positionEyeSpace = vec3(gl_ModelViewMatrix * gl_Vertex);
normalEyeSpace = gl_NormalMatrix * gl_Normal;

// calculate the reflection direction for an incident vector
vec3 I = normalize(positionWorldSpace - cameraPos);
vec3 N = normalize(normalWorldSpace);
vec3 reflectedDirection = normalize(reflect(I, N));

Fragment shader:

#version 130

in vec3 positionEyeSpace;
in vec3 normalEyeSpace;

uniform float farPlane;
uniform bool drawNormal;
uniform bool drawDepth;

out vec4 out_data;

void main() {
vec3 nNormalEyeSpace = normalize(normalEyeSpace);

vec3 nPositionEyeSpace = normalize(-positionEyeSpace);

float linearDepth = sqrt(positionEyeSpace.x * positionEyeSpace.x +
positionEyeSpace.y * positionEyeSpace.y +
positionEyeSpace.z * positionEyeSpace.z);

linearDepth = linearDepth / farPlane;

// output the normal and depth data as matrix
out_data = vec4(0, 0, 0, 1);
if (linearDepth <= 1) {
if (drawNormal) out_data.z = abs(dot(nPositionEyeSpace, nNormalEyeSpace));
if (drawDepth) out_data.y = linearDepth;

gl_FragDepth = linearDepth;

02-28-2018, 05:50 AM
The first surface is easy; as you note, you can just rasterise the surface, calculating the incident vector by subtracting the eye position from the fragment position, then the reflected vector from the incident vector and surface normal. At that point, you have a ray defined by starting position and direction.

That's where it gets complicated: given a ray, you need to find the first surface which that ray intersects. This problem is central to any form of raytracing, whether on the CPU or GPU. If the number of surfaces is small, you can just test each one. Otherwise, you need some form of spatial index (3D array, octree, BSP tree, bounding volume hierarchy etc). Most techniques can be converted to use from GLSL, provided that they don't require specific libraries.

So I would suggest just looking at articles on raytracing in general, finding one which fits your particular scene structure and use case, then figuring out how to implement that in GLSL.

02-28-2018, 02:22 PM
Hi GClements,

thanks for the quick reply. I agree the first surface is easy by rasterization, and the ray properties can be calculated on reflected surface (starting position and direction). My idea is to simulate a single ray for each reflected point, this approach will save computational time. A priori, I have no information about the objects that compose the 3D scene (position, shape...).

This spatial index of each object present in the scene is a good suggestion. I will also look in this direction.

By the way, I still have a doubt: If I use ray tracing for the first surface, and I know a priori the objects' positions, how can I calculate the intersection between the ray and any object surface?

Thanks a lot.

02-28-2018, 03:36 PM

do you have any example with RayTracing and GLSL?

03-01-2018, 01:59 AM
By the way, I still have a doubt: If I use ray tracing for the first surface, and I know a priori the objects' positions, how can I calculate the intersection between the ray and any object surface?

That depends upon the nature of the surface. For a triangle, you'd treat the vertex positions as a 3x3 matrix which transforms barycentric coordinates to spatial coordinates:

[x] [x1 x2 x3] [a]
[y] = [y1 y2 y3].[b]
[z] [z1 z2 z3] [c]

Inverting the matrix gives a matrix M which transforms spatial coordinates to barycentric coordinates.

[a] [x]
[b] = M.[y]
[c] [z]

Note that this only needs to be done once, when the geometry is defined, not every frame.

For each ray p=s+t*d (in world space), transform the start position and direction of the ray into barycentric coordinates:

Finding the intersection with the triangle's plane is just solving a+b+c=1 for t, i.e. u+t*v=1 => t=(1-u)/v where u and v are just the sums of the coordinates of M.s and M.d respectively. Note that if v=0 then the ray is parallel to the plane of the triangle and there is no intersection. Substituting t back into [a b c]T=M.s+t*M.d gives the barycentric coordinates of the intersection point; if all three are positive, the intersection point lies inside the triangle, otherwise it's outside.

do you have any example with RayTracing and GLSL?
Only this (http://www.zen87603.zen.co.uk/webgl/sphere/sphere.html) example of ray-sphere intersection. But it's only the first surface; it doesn't handle reflection. And it's only one object; the spatial index (so you aren't testing every ray against every surface) tends to be the hard part.

03-01-2018, 04:31 PM
Hi GClements,

I'm going to implement this way to store all objects as triangles and pass this information to shader. I will update here with the progresses.