Infinite Loop when Raymarching a Cube

#1

I’m not sure this is the right place to ask this, because this is my first post.

I’m working on a simple ray-marcher in OpenGL. The ray marching is done in the fragment shader of a full-screen quad. The shader code is as follows:

#version 460 core

in vec3 ray_view;

uniform mat4 viewMatrixInv;

vec3 rayDirection_world;
vec3 rayOrigin_world;
vec3 marchPoint;
vec3 normal;
vec3 toEye;
vec3 lightDirection = vec3(3, -1, -1);
vec3 toLight;
vec3 sdfVector;
float sdfValue;

out vec3 color;

const vec3 sphereCenter_world = vec3(0, 0, 0);
const float sphereRadius = 1.0f;

const vec3 cubeCenter_world = vec3(2, 0, 0);
const vec3 cubeDimensions = vec3(1, 1, 1);

vec3 deformationRepeat4(vec3 wp){
	return vec3(
		mod(wp.x + 2, 4) - 2,
		mod(wp.y + 2, 4) - 2,
		mod(wp.z + 2, 4) - 2
	);
}

vec3 reflectAcrossPlane(vec3 n, float offsetFromOrigin, vec3 p) {
	if(dot(n, p) - offsetFromOrigin < 0)
		return p - 2 * n * (dot(normalize(n), p) - offsetFromOrigin);
	return p;
}

float sdfCube(vec3 p) {
	vec3 d = abs(p) - cubeDimensions;
	return length(max(d,0.0))
         + min(max(d.x,max(d.y,d.z)),0.0) - .01;
}

float sdfSphere(vec3 p) {
	return length(abs(p - cubeCenter_world)) - sphereRadius;
}

vec3 deformation(vec3 wp) {
	return wp;
}

float distanceToNearest(vec3 p){
	//First, applies the deformation
	vec3 pDeformed = deformation(p);
	//Then gets the actual sdf of the shape
	return sdfCube(pDeformed - cubeCenter_world);
}

void main() {
	//while(true);
	
	rayDirection_world = (vec3(viewMatrixInv * vec4(normalize(ray_view), 0)));
	rayOrigin_world = vec3(viewMatrixInv * vec4(0, 0, 0, 1));
	
	marchPoint = rayOrigin_world;
	while(true){
		
		sdfValue = distanceToNearest(marchPoint);

		//If the ray has hit the sphere
		if(sdfValue < 0.001){
			//Draw the sphere's color
			//Finds the cube normal
			//vec3 normal = vec3(
			//	(distanceToNearest(vec3(marchPoint.x + 0.001, marchPoint.y, marchPoint.z)) - sdfValue) / 0.001,
			//	(distanceToNearest(vec3(marchPoint.x, marchPoint.y + 0.001, marchPoint.z)) - sdfValue) / 0.001,
			//	(distanceToNearest(vec3(marchPoint.x, marchPoint.y, marchPoint.z + 0.001)) - sdfValue) / 0.001
			//);
			toLight = -normalize(lightDirection);
			toEye = normalize(rayOrigin_world - marchPoint);

			color = vec3(1, 0, 0);// * clamp(dot(normal, toLight), 0, 1) + vec3(1, 1, 1) * pow(clamp(dot(normalize(toLight + toEye), normal), 0, 1), 7); 
			return;
		}

		//If the ray is beyond the distance from the camera
		if(length(marchPoint - rayOrigin_world) > 1000){
			//Draw the background color
			color = vec3(0, 0.5, 0.2);
			return;
		}

		//March the ray forward
		marchPoint += rayDirection_world * sdfValue;
	}

	//color = vec3(distanceToNearest(rayOrigin_world + rayDirection_world) / 15, 0, 0);
}

I compile and run the whole program using Visual Studio 2017. Everything compiles fine and starts to run, but after a few seconds Visual Studio breaks and shows an error message that reads, “Unhandled exception at 0x69CA9C29 (nvoglv32.dll) in GravelMarcher.exe: Fatal program exit requested.”

This is the same error I get when the shader can’t exit and loops forever, but I cannot for the life of me figure out why the shader code would be looping forever. Any input would be greatly appreciated, and I am happy to post whatever extra code I need to.

Thank you in advance for your help!

#2

I found out some more information what might cause the error:

When the line

while(true){

to

for(unsigned int i = 0; i < 1000; i++)

, everything works fine. But when I add a line to the end of the shader outside of the for loop to run if the loop is ever finished to draw white instead of the background color or red, I see no white pixels. This seems to mean that the loop is never finished, but somehow having everything wrapped in a loop changes its behavior?

The plot thickens further. When I change

i < 1000

to

true

so the for loop runs forever, the same problem as with the while loop happens. I have no idea what this all means. Maybe somehow the code is compiled differently? I really don’t know.

Also, this problem seems to be specific to the cube. When I change to the sphere SDF, it works fine.

One more also, this problem seems to only happen when the ‘lowest corner’ of the cube has coordinates above 0. I have no idea how this plays into it.

Any insight is greatly appreciated.