Skip to content

Commit

Permalink
Add Ch1_Ep3 Ray-Sphere Intersect Code & Demo!
Browse files Browse the repository at this point in the history
  • Loading branch information
erichlof committed Sep 20, 2023
1 parent 6c62dc5 commit cdf24f9
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 0 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions Chapter_1/Episode_3/css/rayTracingStyles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
html, body
{
background-color: gray;
margin: 0%;
overflow: hidden;
}

#myCanvas
{
position: fixed;
background-color: black;
width: 100%;
height: 100%;
}

#userInfo
{
position: fixed;
color: white;
bottom: 2%;
left: 1%;
font-family: Arial, Helvetica, sans-serif;
font-size: x-large;
}
15 changes: 15 additions & 0 deletions Chapter_1/Episode_3/intersectSphere.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title> Intersect Sphere </title>
<link href="css/rayTracingStyles.css" rel="stylesheet">
</head>

<body>
<canvas id="myCanvas"> </canvas>
<p id="userInfo"> user text info </p>

<script src="js/mathUtils.js"> </script>
<script src="js/intersectSphere.js"> </script>
</body>
</html>
113 changes: 113 additions & 0 deletions Chapter_1/Episode_3/js/intersectSphere.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
let canvas = document.getElementById("myCanvas");
let context = canvas.getContext("2d");

let aspectRatio = 0;

let userInfo = document.getElementById("userInfo");


window.addEventListener("resize", handleWindowResize);
function handleWindowResize()
{
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

aspectRatio = canvas.width / canvas.height;

userInfo.innerHTML = "canvasW: " + canvas.width + " canvasH: " + canvas.height + "<br>" +
"total pixel count: " + (canvas.width * canvas.height);

// redraw the screen
draw();
}

let canvasX = 0;
let canvasY = 0;

let rayOrigin = new Vector3(0, 0, 0);
let rayDirection = new Vector3();
let colorVector = new Vector3(); // x = r, y = g, z = b

let skyColor = new Vector3(0.2, 0.6, 1.0);
let groundColor = new Vector3(0.5, 0.5, 0.5);
let fogColor = new Vector3(0.7, 0.7, 0.7);
let gradientSkyColor = new Vector3();

let planeOrigin = new Vector3(0, -3, 0);
let planeNormal = new Vector3(0, 1, 0);
planeNormal.normalize();

let sphereRadius = 3;
let spherePosition = new Vector3(0, planeOrigin.y + sphereRadius, -10);
let sphereColor = new Vector3(0.8, 0.01, 0.01);

let t = 0;
let nearestT = 0;

function draw()
{
// loop over all pixels on screen
for (let row = 0; row < canvas.height; row++)
{
for (let column = 0; column < canvas.width; column++)
{
canvasX = column / (canvas.width - 1);
canvasY = row / (canvas.height - 1);
// flip Y coordinates so 0 is bottom of screen and 1 is top of screen
canvasY = 1 - canvasY;
// canvasX goes from 0.0 to 1.0
// canvasY goes from 0.0 to 1.0

canvasX *= 2; // canvasX goes from 0 to 2
canvasY *= 2; // canvasY goes from 0 to 2
canvasX -= 1;
canvasY -= 1;
// canvasX now goes from -1.0 to +1.0 (left to right)
// canvasY now goes from -1.0 to +1.0 (bottom to top)

canvasX *= aspectRatio;
// if (row == 0)
// {
// console.log("canvasX is " + canvasX);
// }

rayDirection.set(canvasX, canvasY, -1);
rayDirection.normalize();

gradientSkyColor.mix(fogColor, skyColor, rayDirection.y * 1.5);

// Important: must reset nearestT for each pixel!
nearestT = Infinity;

t = intersectSphere(spherePosition, sphereRadius, rayOrigin, rayDirection);
if (t < nearestT)
{
nearestT = t;
colorVector.copy(sphereColor);
}

t = intersectPlane(planeOrigin, planeNormal, rayOrigin, rayDirection);
if (t < nearestT)
{
nearestT = t;
colorVector.mix(groundColor, gradientSkyColor, t * 0.008);
}

if (nearestT == Infinity)
{
colorVector.copy(gradientSkyColor);
}

colorVector.multiplyScalar(255);
colorVector.floor();

//"rgb(r,g,b)"
context.fillStyle = "rgb(" + colorVector.x + "," + colorVector.y + "," + colorVector.z + ")";
context.fillRect(column, row, 1, 1);
}
///console.log("canvasY is " + canvasY);
}
} // end function draw()

// jumpstart the drawing of the screen
handleWindowResize();
165 changes: 165 additions & 0 deletions Chapter_1/Episode_3/js/mathUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
function Vector3(x = 0, y = 0, z = 0)
{
this.x = x;
this.y = y;
this.z = z;
return this;
}

Vector3.prototype.set = function(x, y, z)
{
this.x = x;
this.y = y;
this.z = z;
return this;
};

Vector3.prototype.copy = function(otherVector)
{
this.x = otherVector.x;
this.y = otherVector.y;
this.z = otherVector.z;
return this;
};

Vector3.prototype.add = function(otherVector)
{
this.x += otherVector.x;
this.y += otherVector.y;
this.z += otherVector.z;
return this;
};

Vector3.prototype.subtract = function(otherVector)
{
this.x -= otherVector.x;
this.y -= otherVector.y;
this.z -= otherVector.z;
return this;
};

Vector3.prototype.multiplyScalar = function(scalarNumber)
{
this.x *= scalarNumber;
this.y *= scalarNumber;
this.z *= scalarNumber;
return this;
};

Vector3.prototype.floor = function()
{
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
this.z = Math.floor(this.z);
return this;
};

Vector3.prototype.absolute = function()
{
this.x = Math.abs(this.x);
this.y = Math.abs(this.y);
this.z = Math.abs(this.z);
return this;
};

Vector3.prototype.vectorLength = function()
{
return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
};

let inverseLength = 0;
Vector3.prototype.normalize = function()
{
inverseLength = 1 / this.vectorLength();
this.x *= inverseLength;
this.y *= inverseLength;
this.z *= inverseLength;
return this;
};

Vector3.prototype.dot = function(otherVector)
{
return (this.x * otherVector.x) + (this.y * otherVector.y) + (this.z * otherVector.z);
};

Vector3.prototype.mix = function(vectorA, vectorB, t)
{
t = Math.min(t, 1);
t = Math.max(t, 0);
this.x = vectorA.x + (vectorB.x - vectorA.x) * t;
this.y = vectorA.y + (vectorB.y - vectorA.y) * t;
this.z = vectorA.z + (vectorB.z - vectorA.z) * t;
return this;
};


let planeO_rayO_vec = new Vector3();
let rayD_dot_planeN = 0;
let result = 0;

function intersectPlane(planeOrigin, planeNormal, rayOrigin, rayDirection)
{
rayD_dot_planeN = rayDirection.dot(planeNormal);
if (rayD_dot_planeN >= 0)
{
return Infinity;
}

planeO_rayO_vec.copy(planeOrigin);
planeO_rayO_vec.subtract(rayOrigin);
result = planeO_rayO_vec.dot(planeNormal) / rayD_dot_planeN;
if (result > 0)
{
return result;
}

return Infinity;
}

let t0 = 0;
let t1 = 0;
let discriminant = 0;
let oneOver_2a = 0;

function solveQuadratic(a, b, c)
{
discriminant = (b * b) - (4 * a * c);
if (discriminant < 0)
{
return false;
}
discriminant = Math.sqrt(discriminant);
oneOver_2a = 1 / (2 * a);
t0 = (-b - discriminant) * oneOver_2a;
t1 = (-b + discriminant) * oneOver_2a;
return true;
}

let L = new Vector3();
// note: in the video for a, b, and c below, I put them all on one line, such as
// let a, b, c = 0; However, this does not initialize all three to 0 as I had thought.
let a = 0;
let b = 0;
let c = 0;

function intersectSphere(spherePosition, sphereRadius, rayOrigin, rayDirection)
{
L.copy(rayOrigin);
L.subtract(spherePosition);
a = rayDirection.dot(rayDirection);
b = 2 * L.dot(rayDirection);
c = L.dot(L) - (sphereRadius * sphereRadius);
if (solveQuadratic(a, b, c) == false)
{
return Infinity;
}
if (t0 > 0)
{
return t0;
}
else if (t1 > 0)
{
return t1;
}
return Infinity;
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ So...
* Episode 0: [Loop over all pixels and set their colors](https://erichlof.github.io/Joy-of-Ray-Tracing/Chapter_1/Episode_0/pixelLoop.html) - [video](https://youtu.be/bF9MbUKsrRY?list=PL3NuKUKozjGTJRKB4duG2dxpyUu_Pj7jV)
* Episode 1: [Visualize Ray Directions as rgb colors](https://erichlof.github.io/Joy-of-Ray-Tracing/Chapter_1/Episode_1/rayDirections.html) - [video](https://youtu.be/gJ7SMXnVVvY)
* Episode 2: [Ray Intersect Plane, Mix (blend) function](https://erichlof.github.io/Joy-of-Ray-Tracing/Chapter_1/Episode_2/intersectPlane.html) - [video](https://youtu.be/NTieRi0JD5g)
* Episode 3: [Ray Intersect Sphere](https://erichlof.github.io/Joy-of-Ray-Tracing/Chapter_1/Episode_3/intersectSphere.html) - [video](https://youtu.be/BLOnAegyFZE)

0 comments on commit cdf24f9

Please sign in to comment.